diff --git a/.gitattributes b/.gitattributes index bae55fcce..c695ce496 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,16 @@ # .gitattributes + # prevent binary files from CRLF handling, diff and merge: fpga/fpga.bit -crlf -diff *.bin -crlf -diff *.z -crlf -diff - \ No newline at end of file + +# Force LF +*.c text=auto eol=lf +*.cpp text=auto eol=lf +*.h text=auto eol=lf +*.lua text=auto eol=lf +*.py text=auto eol=lf +*.pl text=auto eol=lf +*.dic text=auto eol=lf +Makefile text=auto eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3b04ea5f8..940722506 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,6 +1,9 @@ --- name: Bug report about: Create a report to help us improve +title: '' +labels: '' +assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..ff12e62f1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[idea]" +labels: Request, enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index f3fbe950a..bad050e8f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # don't push these files to the repository .history +.bash_history *.log *.eml *.o @@ -19,6 +20,12 @@ *.exe *.dsym version.c +*.json + +# new build file for add-ons. +Makefile.platform +# Cache for detecting platform def changes +.Makefile.options.cache !client/hardnested/*.bin !client/hardnested/tables/*.z @@ -32,6 +39,7 @@ luac fpga_compress mfkey32 mfkey64 +tools/nonce2key/nonce2key fpga/* !fpga/tests @@ -57,6 +65,6 @@ ppls patches/* *- Copy.* client/lualibs/mf_default_keys.lua -client/lualibs/usb_cmd.lua +client/lualibs/pm3_cmd.lua # recompiled fpga_version_info.c diff --git a/CHANGELOG.md b/CHANGELOG.md index d384e8a61..de1f4f293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,199 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] - + - Change: updates to README (@iceman) + - Change: hf mf/mfu dbg => hw dbg (@doegox) + - Change: replace usb_poll_validate_length() by data_available() that supports USART too (@doegox) + - Make sure standalone modes can be launched when connected on USB without client (@doegox) + - Change: cleaner makefile execution, use 'make V=1' if you want to see full lines (@doegox) + - Change: automate make clean when platform definitions are changed (@doegox) + - Add STANDALONE option to Makefile.hal (@Fl0-0) + - Change: mem info - production public key to verify rdv4.0 flash signature (@iceman) + - Fix specify that we need TCP and not UDP connection (@phcoder) + - Change: lf cotag demod - adjusted error trigger (@iceman) + - Add documentation on BT add-on (@iceman/@doegox) + - Change: new button behaviour in bootloader mode, no need to keep it pressed, press again to interrupt (@doegox) + - Change: new keys in dicts, new mem layout to accomodate them (@iceman/various) + - Fix lf sim - if called with empty graphbuffer all strange things happend, like turning on HF field (@iceman) + - Change: hf 14a sim / hf mf sim - check buttonpress/usb frame fewer times in order not to disrupt simulation (@McEloff) + - Change: data convertbitstream - converts bit to max/min in order to facilitate demodulation of simulation data (@iceman) + - Change: lf em 410x_demod - now can demod the simulation data (@iceman) + - Add HC-06 scripts for BT add-on (@doegox) + - Fix lf nedap sim - error when adding parity (@iceman) + - Add documentation on UART and baudrates (@doegox/@iceman) + - Change: prompt now shows which channel is used (@iceman) + - Change: USART baudrates computation, up to 6Mbps (@iceman/@doegox) + - Change: hf mf nack - keep sync if started without card over antenna + - Add usart btfactory - to reset a misconfigured BT add-on (@doegox) + - Change: hw status - now prints number of dictionary keys loaded (@iceman) + - Add home, end, pageup, and pagedown keybinds to the plot GUI. Also fix paged movement in GUI. (@mcd1992) + - Change legic.lua saves data in EML and BIN formats (@iceman) + - Change hf tune - is now synchronous (for BT add-on) and can be interrupted by kbd (@doegox) + - Change: update macOS install instruction (@ Uli Heilmeier) + - Add trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier) + - Add usart btpin - to change BT add-on PIN (@doegox) + - Add reconnection support (@iceman/@doegox) + - Add usart tx/rx/... - USART developer commands (@doegox) + - Add PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox) + - Fix slow reconfigure on mingw of serial port (@iceman) + - Fix cross thread communictions of timeout variable (@iceman) + - Change: client is now "universal", adapting to Proxmark3 capabilities (@doegox) + - Add disconnect support to Lua (@iceman) + - Change: handles FPC/FLASH FW more gracefully on non-RDV4 pm3 (@doegox) + - Add JTAG support for Shikra (@NinjaStyle82) + - Change: smart color handling: only if linux and on real term (@doegox) + - Change: reconfigure uart timeouts when compiled for FPC and connecting over USB (@iceman) + - Change: fast push for many commands (@iceman/@doegox) + - Add: fast push for Lua (@iceman) + - Add NDEF parser in Lua (@iceman) + - Change: improve NDEF parser (@iceman) + - Change: all commands got migrated to MIX/NG packet format (@iceman/@doegox) + - Fix: Mifare Ultralight read block missing bytes (@doegox) + - Add support new frame format in all Lua scripts (@iceman) + - Add CMD_CAPABILITIES for pm3 to inform dynamically the client (@doegox) + - Change baudrate handling, make it clear it's only indicative for USB-CDC & BT (@doegox) + - Change: new progressive light scheme for 'hw detectreader' (@doegox) + - Add common error definitions system for retvals (@doegox) + - Change USART RX & TX code and fix delays handling to make it more robust, especially over BT (@doegox) + - Add support for new frames format, speedup & huge changes, see doc/new_frame_format.txt (@doegox) + - Change: loadFile* & saveFile* accept filenames with (or still without) extension (@doegox) + - Fix LoadEML to accept final "\n", e.g. from pm3_mfd2eml.py (@doegox) + - Change: rework shell scripts for easy client or flasher (@doegox) + - Fix: stop poking Internet when compiling (@doegox) + - Add support for multiple commands to "-c", e.g. proxmark3 -c "hw ping;hw version" (@doegox) + - Fix external flash writing bitflips issues at 24MHz (@doegox) + - Add color support to Dbprintf & alike and rework Dbprintf flags (@doegox) + - Change: archive (and fix) hid-flasher (@doegox) + - Add standalone placeholder to simplify new standalone integration (@doegox) + - Change: refactor standalone mode info string (@iceman) + - Add iceman skeleton standalone mode for ppl to use as base for their new modes (@iceman) + - Change: move compilation options to Makefile.hal (@doegox) + - Fix compilation under OSX (@iceman) + - Add openocd config files for JLink (@doegox) + - Fix compilation dependencies for recovery (@doegox) + - Fix segfault when loading a file (@doegox) + - Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff) + - Add 'hf mf sim' full-byte split anticollision support (@mceloff) + - Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff) + - Fix serial of FPC. (@ryan) + - Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox) + - Fix 'hf legic info' - unsegmented card now uses card size to calc remaining length (@iceman) + - Add 36bit HID format, extend calcWiegand() to include oem bits ((@davidbeauchamp) + - Fix 'hf mf hardnested' - not verify key when reading nonce file (@iceman) + - Change optimizations for ask/bi (@iceman) + - Fix 'hf mf sim' - bugs fix, refactoring (@mceloff) + - Add WRITE and COMPATIBLE_WRITE support to Mifare Ultralight/NTAG simulation (@mceloff) + - Change installation instructions and add video links (@5w0rdfish) + - Change 'hf mf sim' to support more types (@vratiskol) + - Change better strong wave detection for biphase (@iceman) + - Add 'script run test_t55x7' (@iceman) + - Add new lua scripting support for some t55xx commands (@iceman) + - Add FPC USART for BT add-on with pm3 client. (@doegox) + - Add '-b baudrate' option to the pm3 client. (@doegox) + - Change 'lf t55xx info': tell if known configuration block0. (@iceman) + - Fix/Add FPC usart: fix TX, bring RX, full speed. (@doegox) + - Change 'lf t55xx config' options: allow to toggle on/off i/q5/st + - Change 'lf t55xx info': support offline block0, Q5, fix extended, add warns. (@doegox) + - Avoid race condition when flasher finds the not yet closed pm3 port. (@doegox) + - Fix 'lf t55xx trace': read the proper block. (@doegox) + - Fix Indala 64 on T55xx: use PSK1. (@doegox) + - Force proper Linefeed (LF) handling in ProxSpace. (@vratiskol) + - Fix Makefiles race conditions to allow parallel compilation, e.g. 'make -j8'. (@doegox) + - Add - dictionary key file for MFU. (not in use at the moment) (@mazodude) + - Change 'lf fdx demod - better biphase maxerrors. (@MalteHillmann) + - Change 'hf mf sim' - now works better against android (@mceloff) + - Fix 'lf t55xx brute' - now works after aquiredata adaptations (@iceman) + - Fix 'lf t55xx chk' - now works after aquiredata adaptations (@iceman) + - Fix 'lf t55xx recoverpwd' - now works after aquiredata adaptations (@iceman) + - Fix 'data detect p' - reverted bad clock detection (@iceman) + - Change 'data detect a' - better clock detection (@iceman) + - Add 'hf 14a info' - now detects some magic card Gen2 (@iceman) + - Removed 'LCD' code in armsrc compilation (@iceman) + - Change - Generic fixes of codestyle (@doegox) (@iceman) + - Change 'lf indala demod' - refactoring (@iceman) + - Change - handling fault bit markers (7) and partial nibbles in hex printing (@doegox) + - Change - printing of fault bit markers (7) using a dot (@doegox) + - Change 'sc upgrade' - firmware file integrity check (@piwi) + - Fix 'data rawdemod am' - last bit was missing (@doegox) + - Fix 'hf 15 dump f' - also selects tag first (@iceman) + - Fix 'hf iclass clone' - missing fileclose (@iceman) + - Add 'trace list hitag' - old hitag annotations now use the new trace (@iceman) + - Change 'lf hitag sim' - loads bin/eml/json (@iceman) + - Change 'lf hitag reader 21' - saves in bin/eml/json (@iceman) + - Change 'lf hitag' - refactoring (@iceman) + - Change 'lf hitag' - refactoring (@piwi) + - Fix 'lf hitag' - generic fix for missing clock init (@piwi) + - Fix fsk sim operations on deviceside - avoid division by zero (@doegox) + - Fix 'hf mf fchk' - condition always false (@doegox) + - Fix 'lf t55xx recoverpw' - shift as u32 (@doegox) + - Fix 'lf ti demod' - shift as u32 (@doegox) + - Fix 'lf ti read' - shift as u32 (@doegox) + - Fix 'lf t55xx chk' - condition always false (@doegox) + - Change 'lf sim' - ledcontrol refactoring (@doegox) + - Fix 'hf mf nack' - signedness bug (@doegox) + - Fix 'hf epa cnonce' - check return value (@doegox) + - Fix 'lf hitag write' - condition always true (@doegox) + - Fix 'mem write' - added extra check (@doegox) + - Fix 'iso15693' - bad string cpy (@doegox) + - Fix 'make style' - EOF LF support (@doegox) + - Add 'hf 14b raw' - added -t for timeout (@iceman) + - Rename 'lf hitag snoop' - renamed to 'lf hitag sniff' (@iceman) + - Rename 'lf snoop' - renamed to 'lf sniff' (@iceman) + - Rename 'hf snoop' - renamed to 'hf sniff' (@iceman) + - Fix 'hf mfp wrbl' - more blocks available (@merlokk) + - Add 'make platform' - compile for non-rdv4 devices made simpler (@doegox) + - Change Makefiles optimizations when recompiling (@doegox) + - Fix 'data load' - loads TITEST.txt again (@iceman) + - Change 'lf search' - now detects TI (@iceman) + - Change fixing signal cleaning for LF (@doegox) + - Fix 'lf paradox demod' - wrong check (@iceman) + - Change 'lf t55xx' - aquiredata uses getsamples (@iceman) + - Fix 'lf search' - chipset detection restore demod buffer again (@iceman) + - Add 'make style' (@doegox) + - Fix mixed tabs vs spaces. Now only use 4 space as tab. (@doegox) + - Fix 'lf visa2000 read' - too few samples (@iceman) + - Fix 'lf t55xx bruteforce' - infinity loop (@doegox) + - Fix 'analyse nuid' - correct crc (@doegox) + - Add command history not repeating logged commands (@doegox) + - Fix path for aidjson (@doegox) + - Fix missing init i2x (@doegox) + - Fix '14b select card' - (@doegox) + - Add 'hf mf ndef' - parsing of NDEF messages (@merlokk) + - Add 'hf mf mad' - parsing of Mifare Application Directory (@merlokk) + - Rename 'lf snoop' -> 'lf sniff' (@iceman) + - Rename 'hf snoop' -> 'hf sniff' (@iceman) + - Change generally added more colors (@iceman) + - Change 'sc upgrade' updated firmware v3.11 (RDV40) (@sentiprox) + - Change 'data autocorrelate' - better visual representation and added extra peak detection (@iceman) + - Fix 'lf search' - false positive indala identification fixed (@iceman) + - Add 'lf keri' - basic support for Keri tags (@iceman) + - Add 'hf mf list' - re-added it again (@iceman) + - Fix - A lot of bugfixes, like memory leaks (@iceman) + - Change 'hf 14a antifuzz' - original implementation (@asfabw), reworked a bit + - Fix 'hf mf fchk' (@iceman) + - Fix 'usb slow on posix based systems' (@fl0-0) + - Change 'lf pcf7931' - improved read code (@sguerrini97) + - Change 'hf felica list' - started with some FeliCa annotations (@iceman) + - Fix 'hf tune' - now works as expected (@iceman) + - Add 'option to use flash memory to upload dictionary files' (RDV40) (@iceman) + - Fix 'printing percentage now standard compliant' (@fabled) + - Add 'emv roca' - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman) + - Added TCP ports support (on linux) (@phcoder) + - Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton) + - Fix 'Lining up plot and control window' (@anticat) + - Fix 'annoying focus behaviour' on OSX (@Anticat) + - Implemented AppNap API, fixing #283 and #627 OSX USB comm issues (@AntiCat) + - Added 'sc brute' - a naive SFI bruteforcer for contact smartcards (RDV40) (@iceman) + - Change 'lf t55xx detectconfig' - now optional to persist settings to flashmem (RDV40) (@iceman) + - Change 'hf mf csave' - now saves both EML/BIN formats (@iceman) + - Change 'hf mf esave' - now saves both EML/BIN formats (@iceman) + - Fix 'compiler warning on macos and gcc7.1 or higher' (@TomHarkness) + - Fix 'crash on Bionic libc if CloseProxmark is called twice' (@micolous) + - Change 'lf hid' - got an updated to Kastle format (@xilni) + - Added 'lf t55xx deviceconfig' - enables custom t55xx timing settings. (RDV40) (@iceman) + - Chg adaptations for FPC communications (work in progress) (@iceman) + - Fix 'stand-alone Colin' - remake to benefit from flashmem for persistence. (@cjbrigato) + - Fix 'LEGIC SIM' - remake of legic sim (@drandreas) - Changed 'proxmark3 client threading' - remake from official repo (@micolous) - Add 'rem' - new command that adds a line to the log file (@didierStevens) - Fix 'EM410xdemod empty tag id in lfops.c' (@Defensor7) @@ -65,6 +257,16 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added to `hf 14a apdu` - apdu and tlv results parser (@merlokk) - Added 'hf emv' commands (@merlokk) - lots of bug fixes (many many) + - Changed hf mfp security. Now it works in all the modes. (drHatson) + - Added `hf fido` commands that work with FIDO U2F authenticators (@merlokk) + - Added mbedtls instead of old polarssl (@merlokk) + - Added jansson (@merlokk) + - Added `hf emv scan` - save card's data to json file (@merlokk) + - Added `hf emv` `gpo`, `readrec`, `genac`, `challenge`, `intauth` - separate commands from `hf emc exec` (@merlokk) + - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk) + - Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk) + - Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk) + ### Fixed - Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) - Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok) diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 000000000..dcbdfd34f --- /dev/null +++ b/HACKING.md @@ -0,0 +1,273 @@ +_"Coding styles are like assholes, everyone has one and no one likes anyone elses."_ +--Eric Warmenhoven + +# Overview + +The Proxmark3 codebase is pretty messy and in the process of being cleaned up, +so we don't have clear guidelines on how to place new code just yet. However, +please don't make things worse. + +However, we have established a set of coding style guidelines in order to +clean up the code consistently and keep it consistent in the future. +Look around and respect the same style. + +Helper script to get some uniformity in the style: + +`$ make style` + +It makes use of `astyle` so be sure to install it first. + + +# Indentation + +Don't use tabs, editors are messing them up too easily. +Increment unit is four spaces. + +If you use `make style`, this will be done for you. + +# Width + +Try to keep lines to a reasonable length. 80 characters is a good mark; using an +editor that shows a vertical line is a great idea. However, don't break a line +just because you're slightly over, it's not worth it. No 200-character lines, +though. + +# Macros + +`#define`, function-like or not, are all UPPERCASE unless you're emulating a +well-known function name. + +# Identifiers + +Functions, local variables, and arguments are all named using +`underscores_as_spaces`. Global variables are Evil and are prepended with `g_` to +distinguish them. Avoid them. + +Single-character variables are a bad idea. Exceptions: loop iterators and maybe +simple byte pointers (`*p`) in very obvious places. If you have more than one +such pointer, use a real name. If you have more than a couple nested loops, +complex logic, or indices that differ in interpretation or purpose, use real +names instead of i,j,k. + +# Data types + +Use `stdint.h` types (`uint32_t` and friends) unless you have a reason not to. Don't +use microsoft-style `DWORD` and the like, we're getting rid of those. Avoid char +for buffers, `uint8_t` is more obvious when you're not working with strings. Use +`const` where things are const. Try to use `size_t` for sizes. + +Pointers and reference operators are attached to the variable name: +``` + void *ptr; +``` +not: +``` + void* ptr; +``` +otherwise you're tempted to write: +``` + void* in, out; +``` +and you'll fail. + +`make style` will take care of pointers & reference operators. + +# Expressions + +In general, use whitespace around binary operators - no unspaced blobs of an +expression. `make style` will take care of whitespaces around operators. + +For example, +``` + if (5 * a < b && some_bool_var) +``` +but not +``` + if (5*a= 0x7f) + return '.'; + else + return c; +} +``` +vs. +``` +static void hexdump(void *buf, size_t len) { + ... +} +``` +As a general guideline, functions shouldn't usually be much more than 30-50 +lines. Above, the general algorithm won't be easily apparent, and you're +probably missing some factoring/restructuring opportunity. + +# Structs / unions / enums + +Use typedefs when defining structs. The type should be named something_t. +``` +typedef struct { + blah blah; +} prox_cmd_t; +``` +You can use anonymous enums to replace lots of sequential or mostly-sequential +#defines. + +# Switch + +Indent once for the `case:` labels, then again for the body. Like this: +``` +switch(bar) { + case OPTION_A: + do_stuff(); + break; + case OPTION_B: + do_other_stuff(); + break; +} +``` +`make style` will take care of the indentation. + +If you fall through into another case, add an explicit comment; +otherwise, it can look confusing. + +If your `switch()` is too long or has too many cases, it should be cleaned up. +Split off the cases into functions, break the switch() into parent and children +switches (e.g. command and subcommand), or use an array of function pointers or +the like. In other words, use common sense and your brain. + +If you need local scope variables for a case, you can add braces: +``` +switch(bar) { + case OPTION_A: { + int baz = 5 * bar; + do_stuff(baz); + break; + } + ... +``` +But at that point you should probably consider using a separate function. + +# Comments + +Use //, it's shorter: +``` +// this does foo +... + +// baz: +// This does blah blah blah ..... +// blah blah... +``` +`/* */` can be used to comment blocks of code, but you should probably remove +them anyway - we have version control, it's easy to fetch old code if needed, +so avoid committing commented out chunks of code. The same goes for `#if 0`. + +# File + +Please use common sense and restrain yourself from having a thousands line +file. Functions in a file should have something *specific* in common. Over time +sub-categories can arise and should therefore yield to file splitting. + +For these reasons, vague and general filenames (e.g. `util.*`, `global.*`, `misc.*`, +`main.*`, and the like) should be very limited, if not prohibited. + +# File headers + +License/description header first: +``` +//----------------------------------------------------------------------------- +// YOUR COPYRIGHT LINE GOES HERE +// +// 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. +//----------------------------------------------------------------------------- +// FILE DESCRIPTION GOES HERE +//----------------------------------------------------------------------------- +``` +If you modify a file in any non-trivial way (add code, etc.), add your copyright +to the top with the current year. + +# Header files + +Use the following include guard format: +``` +#ifndef FOOBAR_H__ +#define FOOBAR_H__ + +... + +#endif // FOOBAR_H__ +``` +Keep in mind that `__FOOBAR_H` would be reserved by the implementation and thus +you shouldn't use it (same for `_FOOBAR_H`). + +# Whitespace + +Avoid trailing whitespace (no line should end in tab or space). +Keep a newline (blank line) at the end of each file. + +`make style` will take care of both. diff --git a/HACKING.txt b/HACKING.txt deleted file mode 100644 index fb68142e9..000000000 --- a/HACKING.txt +++ /dev/null @@ -1,291 +0,0 @@ - "Coding styles are like assholes, everyone has one and no one likes anyone elses." - --Eric Warmenhoven - -The Proxmark3 codebase is pretty messy and in the process of being cleaned up, -so we don't have clear guidelines on how to place new code just yet. However, -please don't make things worse. - -However, we have established a set of coding style guidelines in order to -clean up the code consistently and keep it consistent in the future. Use common -sense and good taste. If breaking a rule leads to cleaner code, you can do so, -but laziness is not an excuse. - -=== INDENTATION === - -Use tabs for indentation, but use spaces for alignment: - - if (foo(this, that, there) - && bar == baz) - { - dostuff(); - } - -Notice it's like this (T___ for tab, S for space, for a 4-char tab setting): - -T___if (foo(this, that, there) -T___SSSS&& bar == baz) - -Another example: - -#define THIS 0x10 -#define THAT_THING 0x20 -#define SOMETHING_ELSE 0x80 - -These should look good no matter what your editor's tab setting is, so go nuts -and pick whatever you like best. - -=== WIDTH === - -Try to keep lines to a reasonable length. 80 characters is a good mark; using an -editor that shows a vertical line is a great idea. However, don't break a line -just because you're slightly over, it's not worth it. No 200-character lines, -though. - -=== MACROS === - -#defines, function-like or not, are all UPPERCASE unless you're emulating a -well-known function name. - -=== IDENTIFIERS === - -Functions, local variables, and arguments are all named using -underscores_as_spaces. Global variables are Evil and are prepended with g_ to -distinguish them. Avoid them. - -Single-character variables are a bad idea. Exceptions: loop iterators and maybe -simple byte pointers (*p) in very obvious places. If you have more than one -such pointer, use a real name. If you have more than a couple nested loops, -complex logic, or indices that differ in interpretation or purpose, use real -names instead of i,j,k. - -=== DATA TYPES === - -Use stdint.h types (uint32_t and friends) unless you have a reason not to. Don't -use microsoft-style DWORD and the like, we're getting rid of those. Avoid char -for buffers, uint8_t is more obvious when you're not working with strings. Use -'const' where things are const. Try to use size_t for sizes. - -Pointers are: - void *ptr; -not: - void* ptr; -otherwise you're tempted to write: - void* in, out; -and you'll fail. - -=== EXPRESSIONS === - -In general, use whitespace around binary operators - no unspaced blobs of an -expression. This rule may be broken if it makes things clearer. For example, - - if (5*a < b && some_bool_var) - -but not - - if (5*a 1 line, put braces -around them all. - -=== FUNCTIONS === - -Functions with no arguments are declared as f(void), not f(). Put the return -type on the same line. Use static for functions that aren't exported, and put -exported functions in a header file (one header file per source file with -exported functions usually, no huge headers with all functions). Put a space -after a comma in argument lists. - -void foo(int a_thing, int something_else) -{ - ... -} - -void baz(void) -{ - foo(bluh, blah); -} - -Function names should be separated_with_underscores(), except for standard -functions (memcpy, etc.). It may make sense to break this rule for very common, -generic functions that look like library functions (e.g. dprintf()). - -Don't use single-character arguments. Exception: very short functions with one -argument that's really obvious: - -static int ascii(char c) -{ - if (c < 0x20 || c >= 0x7f) - return '.'; - else - return c; -} - -vs. - -static void hexdump(void *buf, size_t len) -{ - ... -} - -As a general guideline, functions shouldn't usually be much more than 30-50 -lines. Above, the general algorithm won't be easily apparent, and you're -probably missing some factoring/restructuring opportunity. - -=== STRUCTS / UNIONS / ENUMS === - -Use typedefs when defining structs. The type should be named something_t. - -typedef struct { - blah blah; -} prox_cmd_t; - -You can use anonymous enums to replace lots of sequential or mostly-sequential -#defines. - -=== SWITCH === - -Indent once for the case: labels, then again for the body. Like this: - -switch(bar) { - case OPTION_A: - do_stuff(); - break; - case OPTION_B: - do_other_stuff(); - break; -} - -If you fall through into another case, add an explicit comment; otherwise, it -can look confusing. - -If your switch() is too long or has too many cases, it should be cleaned up. -Split off the cases into functions, break the switch() into parent and children -switches (e.g. command and subcommand), or use an array of function pointers or -the like. In other words, use common sense and your brain. - -If you need local scope variables for a case, you can add braces: - -switch(bar) { - case OPTION_A: { - int baz = 5*bar; - do_stuff(baz); - break; - } - ... - -But at that point you should probably consider using a separate function. - -=== COMMENTS === - -Use //, it's shorter: - -// this does foo -... - -// baz: -// This does blah blah blah ..... -// blah blah... - -/* */ can be used to comment blocks of code, but you should probably remove -them anyway - we have version control, it's easy to fetch old code if needed, -so avoid committing commented out chunks of code. The same goes for #if 0. - -=== FILE === - -Please use common sense and restrain yourself from having a thousands+++ line -file. Functions in a file should have something *specific* in common. Over time -sub-categories can arise and should therefore yield to file splitting. - -For these reasons, vague and general filenames (e.g. util.*, global.*, misc.*, -main.*, and the like) should be very limited, if not prohibited. - -=== FILE HEADERS === - -License/description header first: - -//----------------------------------------------------------------------------- -// YOUR COPYRIGHT LINE GOES HERE -// -// 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. -//----------------------------------------------------------------------------- -// FILE DESCRIPTION GOES HERE -//----------------------------------------------------------------------------- - -If you modify a file in any non-trivial way (add code, etc.), add your copyright -to the top. - -=== HEADER FILES === - -Use the following include guard format: - -#ifndef FOOBAR_H__ -#define FOOBAR_H__ - -... - -#endif // FOOBAR_H__ - -Keep in mind that __FOOBAR_H would be reserved by the implementation and thus -you shouldn't use it (same for _FOOBAR_H). - -=== WHITESPACE === - -Avoid trailing whitespace (no line should end in tab or space). People forget -this all the time if their editor doesn't handle it, but don't be surprised if -you see someone fixing it from time to time. - -Keep a newline (blank line) at the end of each file. diff --git a/Makefile b/Makefile index a1c593a76..910aa62f6 100644 --- a/Makefile +++ b/Makefile @@ -1,60 +1,98 @@ +# Hide full compilation line: +ifneq ($(V),1) + Q?=@ +endif +# To see full command lines, use make V=1 + GZIP=gzip # Windows' echo echos its input verbatim, on Posix there is some -# amount of shell command line parsing going on. echo "" on +# 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=\\# + # 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 -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=\\# + # Assume that we are running on native Windows + DELETE=del /q + FLASH_TOOL=client/flasher.exe + platform=Windows + FLASH_PORT=com3 + PATHSEP=\\# endif +-include Makefile.platform +-include .Makefile.options.cache +include common/Makefile.hal + all clean: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mfkey/%: FORCE - $(MAKE) -C tools/mfkey $(patsubst mfkey/%,%,$@) + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C tools/mfkey $(patsubst mfkey/%,%,$@) nonce2key/%: FORCE - $(MAKE) -C tools/nonce2key $(patsubst nonce2key/%,%,$@) -bootrom/%: FORCE - $(MAKE) -C bootrom $(patsubst bootrom/%,%,$@) -armsrc/%: FORCE - $(MAKE) -C armsrc $(patsubst armsrc/%,%,$@) + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C tools/nonce2key $(patsubst nonce2key/%,%,$@) +bootrom/%: FORCE cleanifplatformchanged + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C bootrom $(patsubst bootrom/%,%,$@) +armsrc/%: FORCE cleanifplatformchanged + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C armsrc $(patsubst armsrc/%,%,$@) client/%: FORCE - $(MAKE) -C client $(patsubst client/%,%,$@) -recovery/%: FORCE - $(MAKE) -C recovery $(patsubst recovery/%,%,$@) + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C client $(patsubst client/%,%,$@) +recovery/%: FORCE cleanifplatformchanged bootrom/% armsrc/% + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -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 bootrom flash-bootrom os flash-os flash-all recovery client mfkey nounce2key style checks FORCE udev accessrights cleanifplatformchanged 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 + mfkey - Make tools/mfkey - @echo + nounce2key - Make tools/nounce2key - @echo + clean - Clean in bootrom, armsrc and the OS-specific host directory - + @echo "Multi-OS Makefile" + @echo + @echo "Possible targets:" + @echo "+ all - Make all targets: bootrom, armsrc and OS-specific host tools" + @echo "+ clean - Clean in all targets" + @echo + @echo "+ bootrom - Make bootrom" + @echo "+ os - Make armsrc (includes fpga)" + @echo "+ flash-bootrom - Make bootrom and flash it" + @echo "+ flash-os - Make armsrc and flash os image (includes fpga)" + @echo "+ flash-all - Make bootrom and armsrc and flash bootrom and os image" + @echo "+ recovery - Make bootrom and armsrc images for JTAG flashing" + @echo + @echo "+ client - Make only the OS-specific host client" + @echo "+ mfkey - Make tools/mfkey" + @echo "+ nounce2key - Make tools/nounce2key" + @echo + @echo "+ style - Apply some automated source code formatting rules" + @echo "+ checks - Detect various encoding issues in source code" + @echo + @echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4" + @echo "To activate verbose mode, use make V=1" + client: client/all +bootrom: bootrom/all + +os: armsrc/all + +recovery: recovery/all + +mfkey: mfkey/all + +nonce2key: nonce2key/all + flash-bootrom: bootrom/obj/bootrom.elf $(FLASH_TOOL) $(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$<) @@ -69,24 +107,59 @@ newtarbin: @touch proxmark3-$(platform)-bin.tar tarbin: newtarbin client/tarbin armsrc/tarbin bootrom/tarbin - $(GZIP) proxmark3-$(platform)-bin.tar + $(info GEN proxmark3-$(platform)-bin.tar) + $(Q)$(GZIP) proxmark3-$(platform)-bin.tar -# configure system -# - to ignore PM3 device as a modem (blacklist) -# - add user to the dialout group -# you may need to logout, relogin to get this access right correct. -# Finally, you might need to run the proxmark3 client under SUDO on some systems +# detect if there were changes in the platform definitions, requiring a clean +cleanifplatformchanged: +ifeq ($(PLATFORM_CHANGED), true) + $(info [!] Platform definitions changed, cleaning bootrom/armsrc/recovery first...) + $(Q)$(MAKE) --no-print-directory -C bootrom clean + $(Q)$(MAKE) --no-print-directory -C armsrc clean + $(Q)$(MAKE) --no-print-directory -C recovery clean + $(Q)echo CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache + $(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache + $(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache +endif + +# configure system to ignore PM3 device as a modem (ModemManager blacklist, effective *only* if ModemManager is not using _strict_ policy) +# Read doc/md/ModemManager-Must-Be-Discarded.md for more info udev: sudo cp -rf driver/77-pm3-usb-device-blacklist.rules /etc/udev/rules.d/77-pm3-usb-device-blacklist.rules sudo udevadm control --reload-rules + +# configure system to add user to the dialout group +# you need to logout, relogin to get this access right correct. +# Finally, you might need to run the proxmark3 client under SUDO on some systems +accessrights: ifneq ($(wildcard /etc/arch-release),) #If user is running ArchLinux sudo usermod -aG uucp $(USER) #Use specific command and group else sudo adduser $(USER) dialout endif - + # easy printing of MAKE VARIABLES -print-%: ; @echo $* = $($*) +print-%: ; @echo $* = $($*) + +style: + # Make sure astyle is installed + @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) + # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile + find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" \) \ + -exec perl -pi -e 's/[ \t]+$$//' {} \; \ + -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ + -exec sh -c "echo >> {}" \; + # Apply astyle on *.c, *.h, *.cpp + find . \( -name "*.[ch]" -or -name "*.cpp" \) -exec astyle --formatted --mode=c --suffix=none \ + --indent=spaces=4 --indent-switches \ + --keep-one-line-blocks --max-instatement-indent=60 \ + --style=google --pad-oper --unpad-paren --pad-header \ + --align-pointer=name {} \; + +# Detecting weird codepages. +checks: + find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" \) \ + -exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \; # Dummy target to test for GNU make availability _test: diff --git a/Makefile.platform.sample b/Makefile.platform.sample new file mode 100644 index 000000000..b0d6cf5fe --- /dev/null +++ b/Makefile.platform.sample @@ -0,0 +1,4 @@ +# If you want to use it, copy this file as Makefile.platform and adjust it to your needs +PLATFORM=PM3RDV4 +#PLATFORM_EXTRAS=BTADDON +#STANDALONE=LF_SAMYRUN diff --git a/README.md b/README.md index 7ae1db78c..489a04044 100644 --- a/README.md +++ b/README.md @@ -1,178 +1,76 @@ -Proxmark3 RDV40 dedicated repo, based on iceman fork -=============== +# Proxmark3 RDV4.0 Dedicated Github + +This repo is based on iceman fork for Proxmark3. It is dedicated to bringing the most out of the new features for Proxmark3 RDV4.0 new hardware and design. + +[![Build status](https://ci.appveyor.com/api/projects/status/ct5blik2wa96bv0x/branch/master?svg=true)](https://ci.appveyor.com/project/iceman1001/proxmark3-ji4wj/branch/master) [![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) -## Notice -This repo is based on iceman fork for proxmark3. It is dedicated to bring the most out of the new features for proxmark3 RDV40 device. +--- -## Coverity Scan Config & Run -Download the Coverity Scan Self-buld and install it. -You will need to configure ARM-NON-EABI- Compiler for it to use: +# PROXMARK INSTALLATION AND OVERVIEW -- Configure +| FAQ's & Updates | Installation | Use of the Proxmark | +| ------------------- |:-------------------:| -------------------:| +|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)| +|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) | +|[Why didn't you base it on official PM3 Master?](#why-didnt-you-base-it-on-official-pm3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)| +|[PM3 GUI](#pm3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)| +|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) || +|[Notes on UART](/doc/uart_notes.md)||| +|[Notes on Frame format](/doc/new_frame_format.md)||| +|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) || +|[Donations](#Donations)||| -`cov-configure --comptype gcc --compiler /opt/devkitpro/devkitARM/bin/arm-none-eabi-gcc` +## What has changed? -- Run it (I'm running on Ubuntu) +On the hardware side: -`cov-build --dir cov-int make all` + * added flash memory 256kb. + * added smart card module + * added FPC connector -- Make a tarball - -`tar czvf proxmark3.tgz cov-int` - -- Upload it to coverity.com - - -## Whats changed? - * added flash memory 256kb. - * added smart card module - * added FPC connector - ---- -## Why didn't you based it on offical PM3 Master? -The separation from offical pm3 repo gives us very much freedom to create a firmware/client that suits the RDV40 features. We don't want to mess up the offical pm3 repo with RDV40 specific code. - -## Why don't you add this or that functionality? -Give us a hint, and we'll see if we can't merge in the stuff you have. - -## PM3 GUI -The official PM3-GUI from Gaucho will not work. -The new universial GUI will work. +On the software side: quite a lot, see the [Changelog file](CHANGELOG.md). ## Development This fork now compiles just fine on - Windows/mingw environment with Qt5.6.1 & GCC 4.8 - - Ubuntu 1404, 1510, 1604 + - Ubuntu 1404, 1510, 1604, 1804, 1904 - Mac OS X / Homebrew + - ParrotOS + - WSL (Windows subsystem linux) on Windows 10 - Docker container -## Setup and build for UBUNTU -GC made updates to allow this to build easily on Ubuntu 14.04.2 LTS, 15.10 or 16.04 -See https://github.com/Proxmark/proxmark3/wiki/Ubuntu%20Linux +If you intend to contribute to the code, please read the [coding style notes](HACKING.md) first. -A nice and cool install script made by @daveio is found here: -https://github.com/daveio/attacksurface/blob/master/proxmark3/pm3-setup.sh -I have also added this script to the fork. -https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh - -- Run -`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi` - -- Clone fork -`git clone https://github.com/RfidResearchGroup/proxmark3.git` - -- Get the latest commits -`git pull` - -- Install the blacklist rules and add user to dialout group (if you on a Linux/ubuntu/debian). If you do this one, you need to logout and login in again to make sure your rights got changed. -`make udev` - -- Clean and complete compilation -`make clean && make all` - -- Flash the BOOTROM & FULLIMAGE -`client/flasher /dev/ttyACM0 -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf` - -- Change into the client folder -`cd client` - -- Run the client -`./proxmark3 /dev/ttyACM0` - -## Setup and build for ArchLinux -- Run -`sudo pacman -Sy base-devel p7zip libusb readline ncurses arm-none-eabi-newlib --needed` -`yaourt -S termcap` - -- Clone fork -`git clone https://github.com/RfidResearchGroup/proxmark3.git` - -- Get the latest commits -`git pull` - -- Install the blacklist rules and add user to dialout group (if you on a Linux/ubuntu/debian). If you do this one, you need to logout and login in again to make sure your rights got changed. -`make udev` - -- Clean and complete compilation -`make clean && make all` - -- Flash the BOOTROM & FULLIMAGE -`client/flasher /dev/ttyACM0 -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf` - -- Change into the client folder -`cd client` - -- Run the client -`./proxmark3 /dev/ttyACM0` - -## Homebrew (Mac OS X) -These instructions comes from @Chrisfu, where I got the proxmark3.rb scriptfile from. -Further questions about Mac & Homebrew, contact @Chrisfu (https://github.com/chrisfu/) - -1. Install homebrew if you haven't yet already done so: http://brew.sh/ - -2. Tap this repo: `brew tap RfidResearchGroup/proxmark3` - -3. Install Proxmark3: `brew install proxmark3` for stable release or `brew install --HEAD proxmark3` for latest non-stable from GitHub. - -Upgrading HomeBrew tap formula ------------------------------ -*This method is useful for those looking to run bleeding-edge versions of iceman's client. Keep this in mind when attempting to update your HomeBrew tap formula as this procedure could easily cause a build to break if an update is unstable on macOS.* - -Tested on macOS High Sierra 10.13.2 - -*Note: This assumes you have already installed iceman's fork from HomeBrew as mentioned above* - -1. Force HomeBrew to pull the latest source from github -`brew upgrade --fetch-HEAD RfidResearchGroup/proxmark3` - -2. Flash the bootloader & fullimage.elf - * With your Proxmark3 unplugged from your machine, press and hold the button on your Proxmark 3 as you plug it into a USB port. Continue to hold the button until after this step is complete and the `proxmark3-flasher` command outputs "Have a nice day!"* - `$ sudo proxmark3-flasher /dev/tty.usbmodem881 -b /usr/local/Cellar/proxmark3/HEAD-6a710ef/share/firmware/bootrom.elf /usr/local/Cellar/proxmark3/HEAD-6a710ef/share/firmware/fullimage.elf` +- Internal notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md). +- Internal notes on UART +- Internal notes on Frame format +- Internal notes on standalone mode -`$ sudo proxmark3-flasher /dev/tty.usbmodem881 ` -4. Enjoy the update +## Why didn't you base it on official Proxmark3 Master? +The separation from official Proxmark3 repo gives us a lot of freedom to create a firmware/client that suits the RDV40 features. We don't want to mess up the official Proxmark3 repo with RDV40 specific code. -## Building on Windows +## Proxmark3 GUI +The official PM3-GUI from Gaucho will not work. +The new universal GUI will work. [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) Almost, change needed in order to show helptext when client isn't connected to a device. -### Gator96100 distro -Rather than download and install every one of these packages, a new ProxSpace -environment archive file will be made available for download on the project -page at @Gator96100's repo +## Issues -Afterwards just clone the iceman repo or download someone elses. -Read instructions on @Gator96100 repo page. (https://github.com/Gator96100/ProxSpace/) +Please see the [Proxmark Forum](http://www.proxmark.org/forum/index.php) and see if your issue is listed in the first instance Google is your friend :) Questions will be answered via the forum by Iceman and the team. -Links -- https://github.com/Gator96100/ProxSpace/archive/master.zip -- https://github.com/Gator96100/ProxSpace/releases/tag/v2.2 (release v2.2 with gcc v5.3.0 arm-none-eabi-gcc v7.1.0) +It's needed to have a good USB cable to connect Proxmark3 to USB. If you have stability problems (Proxmark3 resets, firmware hangs, especially firmware hangs just after start, etc.) - check your cable with a USB tester (or try to change it). It needs to have a resistance smaller or equal to 0.3 Ohm. +## The end -### 7. Build and run +- [@herrmann1001](https://mobile.twitter.com/herrmann1001) July 2018 +- updated Feb 2019 [@5w0rdfish](https://mobile.twitter.com/5w0rdFish) -- Clone fork -`git clone https://github.com/RfidResearchGroup/proxmark3.git` +# Donations +Nothing says thank you as much as a donation. So if you feel the love, do feel free to become a iceman patron. For some tiers it comes with rewards. -- Get the latest commits -`git pull` +https://www.patreon.com/iceman1001 -- CLEAN COMPILE -`make clean && make all` - -Assuming you have Proxmark3 Windows drivers installed you can run the Proxmark software where "X" is the com port number assigned to proxmark3 under Windows. - -- Flash the BOOTROM & FULLIMAGE -`client/flasher.exe comX -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf` - -- Change into the client folder -`cd client` - -- Run the client -`proxmark3.exe comX` - -iceman at host iuse.se -July 2018, Sweden +All support is welcome! diff --git a/appveyor.yml b/appveyor.yml index 65aeab1d9..3b937c197 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -66,9 +66,20 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green - Write-Host "Fill msys\etc\fstab file..." -NoNewLine + Write-Host "Fill msys2\etc\fstab file..." -NoNewLine - New-Item c:\ProxSpace\msys\etc\fstab -type file -force -value "#Win32_Path Mount_Point`nc:\ProxSpace\devkitARM /devkitARM`nc:\ProxSpace\Qt\5.6 /qt `nc:\ProxSpace\pm3 /pm3`n" + 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: @@ -84,12 +95,25 @@ install: } build_script: - ps: >- - $env:Path = "C:\ProxSpace\msys\bin;$env:Path" + "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 -lc -i "pwd;make all" + bash -c -i 'pwd;make clean;make all' #some checks @@ -136,6 +160,24 @@ build_script: 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 + + # dll files + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\libgcc_s_dw2-1.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\libstdc++-6.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\libwinpthread-1.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Core.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Gui.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Widgets.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\libreadline*.dll C:\ProxSpace\Release + + Copy-Item C:\ProxSpace\msys2\mingw32\bin\libtermcap-0.dll C:\ProxSpace\Release Write-Host "[ OK ]" -ForegroundColor Green @@ -232,8 +274,8 @@ test_script: #--- end Job [bool]$res=$false - # Wait 60 sec timeout for Job - if(Wait-Job $Job -Timeout 60){ + # Wait 180 sec timeout for Job + if(Wait-Job $Job -Timeout 180){ $Results = $Job | Receive-Job if($Results -like "true"){ $res=$true @@ -268,13 +310,22 @@ test_script: #proxmark logic tests - ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q Execute && echo Passed || echo Failed'} + ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q wait && echo Passed || echo Failed'} - ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'} + ExecTest "proxmark help text ISO7816" "proxmark3 -t" {bash -lc 'cd ~/client;./proxmark3 -t 2>&1 | grep -q ISO7816 && echo Passed || echo Failed'} - ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf'"} "at_enc" + ExecTest "proxmark help text hardnested" "proxmark3 -t" {bash -lc 'cd ~/client;./proxmark3 -t 2>&1 | grep -q hardnested && echo Passed || echo Failed'} + + + ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf'"} "at_enc" + + ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf hardnested t 1 000000000000'"} "found:" + + + #proxmark crypto tests + + ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 -c 'emv test'"} "Test?s? ? OK" - ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:" if ($global:TestsPassed) { Write-Host "Tests [ OK ]" -ForegroundColor Green diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 8f6bf9ca6..7b199930a 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -13,14 +13,14 @@ // 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. // declare it as uint32_t to achieve alignment to 4 Byte boundary -static uint32_t BigBuf[BIGBUF_SIZE/sizeof(uint32_t)]; +static uint32_t BigBuf[BIGBUF_SIZE / sizeof(uint32_t)]; /* BigBuf memory layout: Pointer to highest available memory: BigBuf_hi high BIGBUF_SIZE - reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, - low 0x00 + reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, + low 0x00 */ // High memory mark @@ -30,105 +30,105 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE; static uint8_t *emulator_memory = NULL; // trace related variables -static uint16_t traceLen = 0; -int tracing = 1; //Last global one.. todo static? +static uint32_t traceLen = 0; +static bool tracing = true; //todo static? // get the address of BigBuf uint8_t *BigBuf_get_addr(void) { - return (uint8_t *)BigBuf; + 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; + // 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); + 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); + 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); + memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE); } void BigBuf_Clear_keep_EM(void) { - memset(BigBuf, 0, BigBuf_hi); + 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 + if (BigBuf_hi - chunksize < 0) + return NULL; // no memory left - chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 - BigBuf_hi -= chunksize; // aligned to 4 Byte boundary - return (uint8_t *)BigBuf + BigBuf_hi; + 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; - // shouldn't this empty BigBuf also? +void BigBuf_free(void) { + BigBuf_hi = BIGBUF_SIZE; + emulator_memory = NULL; + // shouldn't this empty BigBuf also? } // 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; - - // shouldn't this empty BigBuf also? + if (emulator_memory != NULL) + BigBuf_hi = emulator_memory - (uint8_t *)BigBuf; + else + BigBuf_hi = BIGBUF_SIZE; + + // shouldn't this empty BigBuf also? } 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); + DbpString(_BLUE_("Memory")); + Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE); + Dbprintf(" Available memory........%d", BigBuf_hi); + DbpString(_BLUE_("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; + return BigBuf_hi; } void clear_trace(void) { - traceLen = 0; + traceLen = 0; } -void set_tracelen(uint16_t value) { +void set_tracelen(uint32_t value) { traceLen = value; } void set_tracing(bool enable) { - tracing = enable; + tracing = enable; } bool get_tracing(void) { - return tracing; + return tracing; } /** * Get the number of bytes traced * @return */ -uint16_t BigBuf_get_traceLen(void) { - return traceLen; +uint32_t BigBuf_get_traceLen(void) { + return traceLen; } /** @@ -138,111 +138,70 @@ uint16_t BigBuf_get_traceLen(void) { 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; + if (!tracing) return false; - uint8_t *trace = BigBuf_get_addr(); + uint8_t *trace = BigBuf_get_addr(); - uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity - uint16_t duration = timestamp_end - timestamp_start; + 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 - if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_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) + // Return when trace is full + if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_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); + // 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); + // duration + trace[traceLen++] = ((duration >> 0) & 0xff); + trace[traceLen++] = ((duration >> 8) & 0xff); - // data length - trace[traceLen++] = ((iLen >> 0) & 0xff); - trace[traceLen++] = ((iLen >> 8) & 0xff); + // data length + trace[traceLen++] = ((iLen >> 0) & 0xff); + trace[traceLen++] = ((iLen >> 8) & 0xff); - // readerToTag flag - if (!readerToTag) { - trace[traceLen - 1] |= 0x80; - } + // readerToTag flag + if (!readerToTag) { + trace[traceLen - 1] |= 0x80; + } - // data bytes - if (btBytes != NULL && iLen != 0) { - memcpy(trace + traceLen, btBytes, iLen); - } - traceLen += iLen; + // data bytes + if (btBytes != NULL && iLen != 0) { + memcpy(trace + traceLen, btBytes, iLen); + } + traceLen += iLen; - // parity bytes - if (num_paritybytes != 0) { - if (parity != NULL) { - memcpy(trace + traceLen, parity, num_paritybytes); - } else { - memset(trace + traceLen, 0x00, num_paritybytes); - } - } - traceLen += num_paritybytes; + // parity bytes + if (num_paritybytes != 0) { + if (parity != NULL) { + memcpy(trace + traceLen, parity, num_paritybytes); + } else { + memset(trace + traceLen, 0x00, num_paritybytes); + } + } + traceLen += num_paritybytes; - 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; - - memcpy(trace + traceLen, btBytes, iLen); - traceLen += iLen; - - return true; + 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; - } - Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE); - return 1; +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; + } + 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 index e8c6f5cd4..12f2521c6 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -17,31 +17,30 @@ #include "string.h" #include "ticks.h" -#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 256 //128 (how big is the dma?!? +#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 256 //128 (how big is the dma?!? -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 void set_tracelen(uint16_t value); -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); +uint8_t *BigBuf_get_addr(void); +uint8_t *BigBuf_get_EM_addr(void); +uint16_t BigBuf_max_traceLen(void); +void BigBuf_Clear(void); +void BigBuf_Clear_ext(bool verbose); +void BigBuf_Clear_keep_EM(void); +void BigBuf_Clear_EM(void); +uint8_t *BigBuf_malloc(uint16_t); +void BigBuf_free(void); +void BigBuf_free_keep_EM(void); +void BigBuf_print_status(void); +uint32_t BigBuf_get_traceLen(void); +void clear_trace(void); +void set_tracing(bool enable); +void set_tracelen(uint32_t value); +bool get_tracing(void); +bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); +uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); #endif /* __BIGBUF_H */ diff --git a/armsrc/LCD.c b/armsrc/LCD.c index b40dba0f7..32a917928 100644 --- a/armsrc/LCD.c +++ b/armsrc/LCD.c @@ -7,143 +7,134 @@ //----------------------------------------------------------------------------- #include "LCD.h" -void LCDSend(unsigned int data) -{ - // 9th bit set for data, clear for command - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete - // For clarity's sake we pass data with 9th bit clear and commands with 9th - // bit set since they're implemented as defines, se we need to invert bit - AT91C_BASE_SPI->SPI_TDR = data^0x100; // Send the data/command +void LCDSend(unsigned int data) { + // 9th bit set for data, clear for command + while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete + // For clarity's sake we pass data with 9th bit clear and commands with 9th + // bit set since they're implemented as defines, se we need to invert bit + AT91C_BASE_SPI->SPI_TDR = data ^ 0x100; // Send the data/command } -void LCDSetXY(unsigned char x, unsigned char y) -{ - LCDSend(PPASET); // page start/end ram - LCDSend(y); // Start Page to display to - LCDSend(131); // End Page to display to +void LCDSetXY(unsigned char x, unsigned char y) { + LCDSend(PPASET); // page start/end ram + LCDSend(y); // Start Page to display to + LCDSend(131); // End Page to display to - LCDSend(PCASET); // column start/end ram - LCDSend(x); // Start Column to display to - LCDSend(131); // End Column to display to + LCDSend(PCASET); // column start/end ram + LCDSend(x); // Start Column to display to + LCDSend(131); // End Column to display to } -void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color) -{ - LCDSetXY(x,y); // Set position - LCDSend(PRAMWR); // Now write the pixel to the display - LCDSend(color); // Write the data in the specified Color +void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color) { + LCDSetXY(x, y); // Set position + LCDSend(PRAMWR); // Now write the pixel to the display + LCDSend(color); // Write the data in the specified Color } -void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color) -{ - unsigned char i,j; +void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned char height, unsigned char color) { + unsigned char i, j; - for (i=0;i < height;i++) // Number of horizontal lines - { - LCDSetXY(xs,ys+i); // Goto start of fill area (Top Left) - LCDSend(PRAMWR); // Write to display + for (i = 0; i < height; i++) { // Number of horizontal lines + LCDSetXY(xs, ys + i); // Goto start of fill area (Top Left) + LCDSend(PRAMWR); // Write to display - for (j=0;j < width;j++) // pixels per line - LCDSend(color); + for (j = 0; j < width; j++) // pixels per line + LCDSend(color); } } -void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor) -{ - unsigned int i; - unsigned char mask=0, px, py, xme, yme, offset; - const char *data; +void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor) { + unsigned int i; + unsigned char mask = 0, px, py, xme, yme, offset; + const char *data; - data = font_style; // point to the start of the font table + data = font_style; // point to the start of the font table - xme = *data; // get font x width - data++; - yme = *data; // get font y length - data++; - offset = *data; // get data bytes per font + xme = *data; // get font x width + data++; + yme = *data; // get font y length + data++; + offset = *data; // get data bytes per font - do - { - // point to data in table to be loaded - data = (font_style + offset) + (offset * (int)(*lcd_string - 32)); + do { + // point to data in table to be loaded + data = (font_style + offset) + (offset * (int)(*lcd_string - 32)); - for (i=0;i < yme;i++) { - mask |=0x80; + for (i = 0; i < yme; i++) { + mask |= 0x80; - for (px=x; px < (x + xme); px++) { - py= y + i; + for (px = x; px < (x + xme); px++) { + py = y + i; - if (*data & mask) LCDSetPixel (px,py,fcolor); - else LCDSetPixel (px,py,bcolor); + if (*data & mask) LCDSetPixel(px, py, fcolor); + else LCDSetPixel(px, py, bcolor); - mask>>=1; - } - data++; - } - x+=xme; + mask >>= 1; + } + data++; + } + x += xme; - lcd_string++; // next character in string + lcd_string++; // next character in string - } while(*lcd_string !='\0'); // keep spitting chars out until end of string + } while (*lcd_string != '\0'); // keep spitting chars out until end of string } -void LCDReset(void) -{ - LED_A_ON(); - SetupSpi(SPI_LCD_MODE); - LOW(GPIO_LRST); - SpinDelay(100); +void LCDReset(void) { + LED_A_ON(); + SetupSpi(SPI_LCD_MODE); + LOW(GPIO_LRST); + SpinDelay(100); - HIGH(GPIO_LRST); - SpinDelay(100); - LED_A_OFF(); + HIGH(GPIO_LRST); + SpinDelay(100); + LED_A_OFF(); } -void LCDInit(void) -{ - int i; +void LCDInit(void) { + int i; - LCDReset(); + LCDReset(); - LCDSend(PSWRESET); // software reset - SpinDelay(100); - LCDSend(PSLEEPOUT); // exit sleep mode - LCDSend(PBSTRON); // booster on - LCDSend(PDISPON); // display on - LCDSend(PNORON); // normal on - LCDSend(PMADCTL); // rotate display 180 deg - LCDSend(0xC0); + LCDSend(PSWRESET); // software reset + SpinDelay(100); + LCDSend(PSLEEPOUT); // exit sleep mode + LCDSend(PBSTRON); // booster on + LCDSend(PDISPON); // display on + LCDSend(PNORON); // normal on + LCDSend(PMADCTL); // rotate display 180 deg + LCDSend(0xC0); - LCDSend(PCOLMOD); // color mode - LCDSend(0x02); // 8bpp color mode + LCDSend(PCOLMOD); // color mode + LCDSend(0x02); // 8bpp color mode - LCDSend(PSETCON); // set contrast + LCDSend(PSETCON); // set contrast LCDSend(0xDC); - // clear display - LCDSetXY(0,0); - LCDSend(PRAMWR); // Write to display - i=LCD_XRES*LCD_YRES; - while(i--) LCDSend(WHITE); - - // test text on different colored backgrounds - LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK ); - LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE ); - LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED ); - LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN ); - LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE ); - LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW); - LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN ); - LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA); - - // color bands - LCDFill(0, 1+8* 8, 132, 8, BLACK); - LCDFill(0, 1+8* 9, 132, 8, WHITE); - LCDFill(0, 1+8*10, 132, 8, RED); - LCDFill(0, 1+8*11, 132, 8, GREEN); - LCDFill(0, 1+8*12, 132, 8, BLUE); - LCDFill(0, 1+8*13, 132, 8, YELLOW); - LCDFill(0, 1+8*14, 132, 8, CYAN); - LCDFill(0, 1+8*15, 132, 8, MAGENTA); + // clear display + LCDSetXY(0, 0); + LCDSend(PRAMWR); // Write to display + i = LCD_XRES * LCD_YRES; + while (i--) LCDSend(WHITE); + + // test text on different colored backgrounds + LCDString(" The quick brown fox ", (char *)&FONT6x8, 1, 1 + 8 * 0, WHITE, BLACK); + LCDString(" jumped over the ", (char *)&FONT6x8, 1, 1 + 8 * 1, BLACK, WHITE); + LCDString(" lazy dog. ", (char *)&FONT6x8, 1, 1 + 8 * 2, YELLOW, RED); + LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8, 1, 1 + 8 * 3, RED, GREEN); + LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8, 1, 1 + 8 * 4, MAGENTA, BLUE); + LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8, 1, 1 + 8 * 5, BLUE, YELLOW); + LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8, 1, 1 + 8 * 6, BLACK, CYAN); + LCDString(" _+{}|:\\\"<>? ", (char *)&FONT6x8, 1, 1 + 8 * 7, BLUE, MAGENTA); + + // color bands + LCDFill(0, 1 + 8 * 8, 132, 8, BLACK); + LCDFill(0, 1 + 8 * 9, 132, 8, WHITE); + LCDFill(0, 1 + 8 * 10, 132, 8, RED); + LCDFill(0, 1 + 8 * 11, 132, 8, GREEN); + LCDFill(0, 1 + 8 * 12, 132, 8, BLUE); + LCDFill(0, 1 + 8 * 13, 132, 8, YELLOW); + LCDFill(0, 1 + 8 * 14, 132, 8, CYAN); + LCDFill(0, 1 + 8 * 15, 132, 8, MAGENTA); } diff --git a/armsrc/LCD.h b/armsrc/LCD.h index 2643f66ee..968c90246 100644 --- a/armsrc/LCD.h +++ b/armsrc/LCD.h @@ -14,117 +14,117 @@ #include "fonts.h" // The resolution of the LCD -#define LCD_XRES 132 -#define LCD_YRES 132 +#define LCD_XRES 132 +#define LCD_YRES 132 // 8bpp Color Mode - Some basic colors defined for ease of use // remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits // organised as RRRGGGBB -#define BLACK 0x00 -#define BLUE 0x03 -#define GREEN 0x1C -#define CYAN 0x1F -#define RED 0xE0 -#define MAGENTA 0xE3 -#define YELLOW 0xFC -#define WHITE 0xFF +#define BLACK 0x00 +#define BLUE 0x03 +#define GREEN 0x1C +#define CYAN 0x1F +#define RED 0xE0 +#define MAGENTA 0xE3 +#define YELLOW 0xFC +#define WHITE 0xFF // EPSON LCD command set -#define ECASET 0x115 -#define EPWRCTR 0x120 -#define ENOP 0x125 -#define ERAMWR 0x15C -#define ERAMRD 0x15D -#define EPASET 0x175 -#define EEPSRRD1 0x17C -#define EEPSRRD2 0x17D -#define EVOLCTR 0x181 -#define ETMPGRD 0x182 -#define ESLPOUT 0x194 -#define ESLPIN 0x195 -#define EDISNOR 0x1A6 -#define EDISINV 0x1A7 -#define EPTLIN 0x1A8 -#define EPTLOUT 0x1A9 -#define EASCSET 0x1AA -#define ESCSTART 0x1AB -#define EDISOFF 0x1AE -#define EDISON 0x1AF -#define ECOMSCN 0x1BB -#define EDATCTL 0x1BC -#define EDISCTL 0x1CA -#define EEPCOUT 0x1CC -#define EEPCTIN 0x1CD -#define ERGBSET8 0x1CE -#define EOSCON 0x1D1 -#define EOSCOFF 0x1D2 -#define EVOLUP 0x1D6 -#define EVOLDOWN 0x1D7 -#define ERMWIN 0x1E0 -#define ERMWOUT 0x1EE -#define EEPMWR 0x1FC -#define EEPMRD 0x1FD +#define ECASET 0x115 +#define EPWRCTR 0x120 +#define ENOP 0x125 +#define ERAMWR 0x15C +#define ERAMRD 0x15D +#define EPASET 0x175 +#define EEPSRRD1 0x17C +#define EEPSRRD2 0x17D +#define EVOLCTR 0x181 +#define ETMPGRD 0x182 +#define ESLPOUT 0x194 +#define ESLPIN 0x195 +#define EDISNOR 0x1A6 +#define EDISINV 0x1A7 +#define EPTLIN 0x1A8 +#define EPTLOUT 0x1A9 +#define EASCSET 0x1AA +#define ESCSTART 0x1AB +#define EDISOFF 0x1AE +#define EDISON 0x1AF +#define ECOMSCN 0x1BB +#define EDATCTL 0x1BC +#define EDISCTL 0x1CA +#define EEPCOUT 0x1CC +#define EEPCTIN 0x1CD +#define ERGBSET8 0x1CE +#define EOSCON 0x1D1 +#define EOSCOFF 0x1D2 +#define EVOLUP 0x1D6 +#define EVOLDOWN 0x1D7 +#define ERMWIN 0x1E0 +#define ERMWOUT 0x1EE +#define EEPMWR 0x1FC +#define EEPMRD 0x1FD // PHILIPS LCD command set -#define PNOP 0x100 -#define PSWRESET 0x101 -#define PBSTROFF 0x102 -#define PBSTRON 0x103 -#define PRDDIDIF 0x104 -#define PRDDST 0x109 -#define PSLEEPIN 0x110 -#define PSLEEPOUT 0x111 -#define PPTLON 0x112 -#define PNORON 0x113 -#define PINVOFF 0x120 -#define PINVON 0x121 -#define PDALO 0x122 -#define PDAL 0x123 -#define PSETCON 0x125 -#define PDISPOFF 0x128 -#define PDISPON 0x129 -#define PCASET 0x12A -#define PPASET 0x12B -#define PRAMWR 0x12C -#define PRGBSET 0x12D -#define PPTLAR 0x130 -#define PVSCRDEF 0x133 -#define PTEOFF 0x134 -#define PTEON 0x135 -#define PMADCTL 0x136 -#define PSEP 0x137 -#define PIDMOFF 0x138 -#define PIDMON 0x139 -#define PCOLMOD 0x13A -#define PSETVOP 0x1B0 -#define PBRS 0x1B4 -#define PTRS 0x1B6 -#define PFINV 0x1B9 -#define PDOR 0x1BA -#define PTCDFE 0x1BD -#define PTCVOPE 0x1BF -#define PEC 0x1C0 -#define PSETMUL 0x1C2 -#define PTCVOPAB 0x1C3 -#define PTCVOPCD 0x1C4 -#define PTCDF 0x1C5 -#define PDF8C 0x1C6 -#define PSETBS 0x1C7 -#define PRDTEMP 0x1C8 -#define PNLI 0x1C9 -#define PRDID1 0x1DA -#define PRDID2 0x1DB -#define PRDID3 0x1DC -#define PSFD 0x1EF -#define PECM 0x1F0 +#define PNOP 0x100 +#define PSWRESET 0x101 +#define PBSTROFF 0x102 +#define PBSTRON 0x103 +#define PRDDIDIF 0x104 +#define PRDDST 0x109 +#define PSLEEPIN 0x110 +#define PSLEEPOUT 0x111 +#define PPTLON 0x112 +#define PNORON 0x113 +#define PINVOFF 0x120 +#define PINVON 0x121 +#define PDALO 0x122 +#define PDAL 0x123 +#define PSETCON 0x125 +#define PDISPOFF 0x128 +#define PDISPON 0x129 +#define PCASET 0x12A +#define PPASET 0x12B +#define PRAMWR 0x12C +#define PRGBSET 0x12D +#define PPTLAR 0x130 +#define PVSCRDEF 0x133 +#define PTEOFF 0x134 +#define PTEON 0x135 +#define PMADCTL 0x136 +#define PSEP 0x137 +#define PIDMOFF 0x138 +#define PIDMON 0x139 +#define PCOLMOD 0x13A +#define PSETVOP 0x1B0 +#define PBRS 0x1B4 +#define PTRS 0x1B6 +#define PFINV 0x1B9 +#define PDOR 0x1BA +#define PTCDFE 0x1BD +#define PTCVOPE 0x1BF +#define PEC 0x1C0 +#define PSETMUL 0x1C2 +#define PTCVOPAB 0x1C3 +#define PTCVOPCD 0x1C4 +#define PTCDF 0x1C5 +#define PDF8C 0x1C6 +#define PSETBS 0x1C7 +#define PRDTEMP 0x1C8 +#define PNLI 0x1C9 +#define PRDID1 0x1DA +#define PRDID2 0x1DB +#define PRDID3 0x1DC +#define PSFD 0x1EF +#define PECM 0x1F0 void LCDSend(unsigned int data); void LCDInit(void); void LCDReset(void); void LCDSetXY(unsigned char x, unsigned char y); void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color); -void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor); -void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color); +void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor); +void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned char height, unsigned char color); #endif diff --git a/armsrc/Makefile b/armsrc/Makefile index d70008e0c..7fda76b99 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -1,4 +1,3 @@ -#----------------------------------------------------------------------------- # 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. @@ -8,103 +7,101 @@ APP_INCLUDES = apps.h +# This Makefile might have been called directly, not via the root Makefile, so: +ifeq ($(PLTNAME),) + -include ../Makefile.platform + -include ../.Makefile.options.cache + include ../common/Makefile.hal +# detect if there were changes in the platform definitions, requiring a clean + ifeq ($(PLATFORM_CHANGED), true) + $(error platform definitions have been changed, please "make clean" at the root of the project) + endif +endif + #remove one of the following defines and comment out the relevant line #in the next section to remove that particular feature from compilation. -# NO space,TABs after the "\" sign. -APP_CFLAGS = -DWITH_CRC \ - -DON_DEVICE \ - -DWITH_LF \ - -DWITH_HITAG \ - -DWITH_ISO15693 \ - -DWITH_LEGICRF \ - -DWITH_ISO14443b \ - -DWITH_ISO14443a \ - -DWITH_ICLASS \ - -DWITH_FELICA \ - -DWITH_FLASH \ - -DWITH_SMARTCARD \ - -DWITH_HFSNOOP \ - -DWITH_LF_SAMYRUN \ - -DWITH_FPC \ - -fno-strict-aliasing -ffunction-sections -fdata-sections +# NO space,TABs after the "\" sign. +APP_CFLAGS = $(PLATFORM_DEFS) \ + -DON_DEVICE \ + -fno-strict-aliasing -ffunction-sections -fdata-sections -### IMPORTANT - move the commented variable below this line -# -DWITH_LCD \ -# -DWITH_EMV \ -# -DWITH_FPC \ -# -# Standalone Mods -#------------------------------------------------------- -# -DWITH_LF_ICERUN -# -DWITH_LF_SAMYRUN -# -DWITH_LF_PROXBRUTE -# -DWITH_LF_HIDBRUTE -# -DWITH_HF_YOUNG -# -DWITH_HF_MATTYRUN -# -DWITH_HF_COLIN - - -SRC_LCD = fonts.c LCD.c -SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c +SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c SRC_ISO15693 = iso15693.c iso15693tools.c -#SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c -SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c +SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c SRC_ISO14443b = iso14443b.c SRC_FELICA = felica.c SRC_CRAPTO1 = crypto1.c des.c aes.c desfire_key.c desfire_crypto.c mifaredesfire.c -SRC_CRC = crc.c crc16.c crc32.c +SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipher.c -SRC_LEGIC = legicrf.c legic_prng.c -SRC_BEE = bee.c +SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c +# SRC_BEE = bee.c # RDV40 related hardware support ifneq (,$(findstring WITH_FLASH,$(APP_CFLAGS))) - SRC_FLASH = flashmem.c + SRC_FLASH = flashmem.c else - SRC_FLASH = + SRC_FLASH = endif ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS))) - SRC_SMARTCARD = i2c.c + SRC_SMARTCARD = i2c.c else - SRC_SMARTCARD = + SRC_SMARTCARD = endif -ifneq (,$(findstring WITH_FPC,$(APP_CFLAGS))) - SRC_FPC = usart.c +ifneq (,$(findstring WITH_FPC_USART,$(APP_CFLAGS))) + SRC_FPC = usart.c else - SRC_FPC = + SRC_FPC = +endif + +ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS))) + SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c +else + SRC_HITAG = +endif + +ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS))) + SRC_LCD = fonts.c LCD.c +else + SRC_LCD = endif # Generic standalone Mode injection of source code -SRC_STANDALONE = -# WITH_LF_ICERUN -ifneq (,$(findstring WITH_LF_ICERUN,$(APP_CFLAGS))) - SRC_STANDALONE = + + +SRC_STANDALONE = placeholder.c +# WITH_STANDALONE_LF_ICERUN +ifneq (,$(findstring WITH_STANDALONE_LF_ICERUN,$(APP_CFLAGS))) + SRC_STANDALONE = lf_icerun.c endif -# WITH_LF_SAMYRUN -ifneq (,$(findstring WITH_LF_SAMYRUN,$(APP_CFLAGS))) - SRC_STANDALONE = lf_samyrun.c +# WITH_STANDALONE_LF_SAMYRUN +ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS))) + SRC_STANDALONE = lf_samyrun.c endif -# WITH_LF_PROXBRUTE -ifneq (,$(findstring WITH_LF_PROXBRUTE,$(APP_CFLAGS))) - SRC_STANDALONE = lf_proxbrute.c +# WITH_STANDALONE_LF_PROXBRUTE +ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS))) + SRC_STANDALONE = lf_proxbrute.c endif -# WITH_LF_HIDBRUTE -ifneq (,$(findstring WITH_LF_HIDBRUTE,$(APP_CFLAGS))) - SRC_STANDALONE = lf_hidbrute.c +# WITH_STANDALONE_LF_HIDBRUTE +ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS))) + SRC_STANDALONE = lf_hidbrute.c endif -# WITH_HF_YOUNG -ifneq (,$(findstring WITH_HF_YOUNG,$(APP_CFLAGS))) - SRC_STANDALONE = hf_young.c +# WITH_STANDALONE_HF_YOUNG +ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS))) + SRC_STANDALONE = hf_young.c endif -# WITH_HF_MATTYRUN -ifneq (,$(findstring WITH_HF_MATTYRUN,$(APP_CFLAGS))) - SRC_STANDALONE = hf_mattyrun.c +# WITH_STANDALONE_HF_MATTYRUN +ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS))) + SRC_STANDALONE = hf_mattyrun.c endif -# WITH_HF_COLIN -ifneq (,$(findstring WITH_HF_COLIN,$(APP_CFLAGS))) - SRC_STANDALONE = hf_colin.c vtsend.c +# WITH_STANDALONE_HF_COLIN +ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS))) + SRC_STANDALONE = vtsend.c hf_colin.c +endif +# WITH_STANDALONE_HF_BOG +ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS))) + SRC_STANDALONE = hf_bog.c endif #the FPGA bitstream files. Note: order matters! @@ -118,109 +115,131 @@ APP_CFLAGS += $(ZLIB_CFLAGS) # zlib includes: APP_CFLAGS += -I../zlib -# stdint.h provided locally until GCC 4.5 becomes C99 compliant -APP_CFLAGS += -I. +# stdint.h provided locally until GCC 4.5 becomes C99 compliant, +# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc +APP_CFLAGS += -I. -fno-stack-protector -fno-pie # Compile these in thumb mode (small size) THUMBSRC = start.c \ - protocols.c \ - $(SRC_LCD) \ - $(SRC_ISO15693) \ - $(SRC_LF) \ - $(SRC_ZLIB) \ - $(SRC_LEGIC) \ - $(SRC_FLASH) \ - $(SRC_SMARTCARD) \ - $(SRC_FPC) \ - appmain.c \ - printf.c \ - util.c \ - string.c \ - BigBuf.c \ - ticks.c \ - random.c \ - hfsnoop.c + protocols.c \ + $(SRC_LCD) \ + $(SRC_ISO15693) \ + $(SRC_LF) \ + $(SRC_ZLIB) \ + $(SRC_LEGIC) \ + $(SRC_FLASH) \ + $(SRC_SMARTCARD) \ + $(SRC_FPC) \ + $(SRC_HITAG) \ + appmain.c \ + printf.c \ + commonutil.c \ + util.c \ + string.c \ + BigBuf.c \ + ticks.c \ + hfsnoop.c # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ - $(SRC_ISO14443a) \ - $(SRC_ISO14443b) \ - $(SRC_CRAPTO1) \ - $(SRC_ICLASS) \ - $(SRC_EMV) \ - $(SRC_CRC) \ - $(SRC_FELICA) \ - $(SRC_STANDALONE) \ - parity.c \ - usb_cdc.c \ - cmd.c - + $(SRC_ISO14443a) \ + $(SRC_ISO14443b) \ + $(SRC_CRAPTO1) \ + $(SRC_ICLASS) \ + $(SRC_EMV) \ + $(SRC_CRC) \ + $(SRC_FELICA) \ + $(SRC_STANDALONE) \ + parity.c \ + usb_cdc.c \ + cmd.c + VERSIONSRC = version.c \ - fpga_version_info.c - + fpga_version_info.c + # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common -COMMON_FLAGS = -Os +COMMON_FLAGS = -Os -OBJS = $(OBJDIR)/fullimage.s19 +OBJS = $(OBJDIR)/fullimage.s19 FPGA_COMPRESSOR = ../client/fpga_compress all: $(OBJS) .DELETE_ON_ERROR: -# version.c should be remade on every compilation -.PHONY: version.c -version.c: default_version.c - perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ +# version.c should be remade on every time fullimage.stage1.elf should be remade +version.c: default_version.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) + $(info [-] GEN $@) + $(Q)perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@ + $(info [-] GEN $@) + $(Q)$(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 $^ $@ + $(info [-] GEN $@) + $(Q)$(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,$^) $@ + $(info [-] GEN $@) +ifeq ($(Q),@) + @$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ >/dev/null +else + $(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ +endif $(FPGA_COMPRESSOR): - make -C ../client $(notdir $(FPGA_COMPRESSOR)) - + $(info [*] MAKE $@) + $(Q)$(MAKE) --no-print-directory -C ../client $(notdir $(FPGA_COMPRESSOR)) + $(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) - $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) + $(info [=] LD $@) + $(Q)$(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 $^ $@ - + $(info [-] GEN $@) + $(Q)$(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@ + $(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@ + $(info [-] GEN $@) + $(Q)$(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 $^ $@ + $(info [-] GEN $@) + $(Q)$(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@ $(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ - + $(info [-] GEN $@) +ifeq ($(Q),@) + @$(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ >/dev/null +else + $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ +endif + $(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ + $(info [-] GEN $@) + $(Q)$(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 $@ $^ + $(info [=] LD $@) + $(Q)$(CC) $(LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ tarbin: $(OBJS) - $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf) + $(info TAR $@) + $(Q)$(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 + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.o + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.elf + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.s19 + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.map + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.d + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.z + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.bin + $(Q)$(DELETE) version.c .PHONY: all clean help help: diff --git a/armsrc/Standalone/hf_bog.c b/armsrc/Standalone/hf_bog.c new file mode 100644 index 000000000..0ee0a9066 --- /dev/null +++ b/armsrc/Standalone/hf_bog.c @@ -0,0 +1,303 @@ +//----------------------------------------------------------------------------- +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// main code for standalone HF Sniff (and ULC/NTAG/ULEV1 pwd storing) +//----------------------------------------------------------------------------- + +/* +This can actually be used in two separate ways. +It can either be used to just HF 14a sniff on the go and/or grab the +authentication attempts for ULC/NTAG/ULEV1 into the flash mem (RDV4). + +The retrieved sniffing session can be acquired by connecting the device +to a client that supports the reconnect capability and issue 'hf 14a list'. + +In order to view the grabbed authentication attempts in the flash mem, +you can simply run 'script run read_pwd_mem' or just 'mem read l 256' +from the client to view the stored quadlets. +*/ + +#include "hf_bog.h" + +#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) +#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) + +// Maximum number of auth attempts per standalone session +#define MAX_PWDS_PER_SESSION 64 + +uint8_t FindOffsetInFlash() { + uint8_t mem[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint8_t eom[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; + uint8_t memcnt = 0; + + while (memcnt < 0xFF) { + Flash_ReadData(memcnt, mem, 4); + if (memcmp(mem, eom, 4) == 0) { + return memcnt; + } + memcnt += 4; + } + + return 0; // wrap-around +} + +void EraseMemory() { + if (!FlashInit()) { + return; + } + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase4k(0, 0); + + if (DBGLEVEL > 1) Dbprintf("[!] Erased flash!"); + FlashStop(); + SpinDelay(100); +} + +// This is actually copied from SniffIso14443a +void RAMFUNC SniffAndStore(uint8_t param) { + + iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); + + // Allocate memory from BigBuf for some buffers + // free all previous allocations first + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + // Array to store the authpwds + uint8_t *capturedPwds = BigBuf_malloc(4 * MAX_PWDS_PER_SESSION); + + // 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 *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); + + // The DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + uint8_t *data = dmaBuf; + + uint8_t previous_data = 0; + int dataLen; + bool TagIsActive = false; + bool ReaderIsActive = false; + + // Set up the demodulator for tag -> reader responses. + DemodInit(receivedResp, receivedRespPar); + + // Set up the demodulator for the reader -> tag commands + UartInit(receivedCmd, receivedCmdPar); + + // Setup and start DMA. + if (!FpgaSetupSscDma((uint8_t *) dmaBuf, DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return; + } + + tUart *uart = GetUart(); + tDemod *demod = GetDemod(); + + // 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); + + uint32_t my_rsamples = 0; + + // Current captured passwords counter + uint8_t auth_attempts = 0; + + SpinDelay(50); + + // loop and listen + while (!BUTTON_PRESS()) { + WDT_HIT(); + LED_A_ON(); + + int register readBufDataP = data - dmaBuf; + int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; + if (readBufDataP <= dmaBufDataP) + dataLen = dmaBufDataP - readBufDataP; + else + dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; + + // test for length of buffer + if (dataLen > DMA_BUFFER_SIZE) { // TODO: Check if this works properly + Dbprintf("[!] blew circular buffer! | datalen %u", dataLen); + break; + } + if (dataLen < 1) continue; + + // primary buffer was stopped( <-- we lost data! + if (!AT91C_BASE_PDC_SSC->PDC_RCR) { + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; + //Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary + } + // secondary buffer sets as primary, secondary buffer was stopped + if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } + + LED_A_OFF(); + + // Need two samples to feed Miller and Manchester-Decoder + if (my_rsamples & 0x01) { + + 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, (my_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) { + if ((receivedCmd) && ((receivedCmd[0] == MIFARE_ULEV1_AUTH) || (receivedCmd[0] == MIFARE_ULC_AUTH_1))) { + if (DBGLEVEL > 1) Dbprintf("PWD-AUTH KEY: 0x%02x%02x%02x%02x", receivedCmd[1], receivedCmd[2], receivedCmd[3], receivedCmd[4]); + + // temporarily save the captured pwd in our array + memcpy(&capturedPwds[4 * auth_attempts], receivedCmd + 1, 4); + auth_attempts++; + } + + 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; + } + /* ready to receive another command. */ + UartReset(); + /* 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); + } + + // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { + uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); + if (ManchesterDecoding(tagdata, 0, (my_rsamples - 1) * 4)) { + LED_B_ON(); + + if (!LogTrace(receivedResp, + 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; + + // ready to receive another response. + DemodReset(); + // reset the Miller decoder including its (now outdated) input buffer + UartReset(); + //UartInit(receivedCmd, receivedCmdPar); + LED_C_OFF(); + } + TagIsActive = (demod->state != DEMOD_UNSYNCD); + } + } + + previous_data = *data; + my_rsamples++; + data++; + if (data == dmaBuf + DMA_BUFFER_SIZE) { + data = dmaBuf; + } + } // end main loop + + FpgaDisableSscDma(); + set_tracing(false); + + Dbprintf("Stopped sniffing"); + + SpinDelay(200); + + // Write stuff to flash + if (auth_attempts > 0) { + if (DBGLEVEL > 1) Dbprintf("[!] Authentication attempts = %u", auth_attempts); + + // Setting the SPI Baudrate to 48MHz to avoid the bit-flip issue (https://github.com/RfidResearchGroup/proxmark3/issues/34) + FlashmemSetSpiBaudrate(48000000); + + // Find the offset in flash mem to continue writing the auth attempts + uint8_t memoffset = FindOffsetInFlash(); + if (DBGLEVEL > 1) Dbprintf("[!] Memory offset = %u", memoffset); + + if ((memoffset + 4 * auth_attempts) > 0xFF) { + // We opt to keep the new data only + memoffset = 0; + if (DBGLEVEL > 1) Dbprintf("[!] Size of total data > 256 bytes. Discarding the old data."); + } + + // Get previous data from flash mem + uint8_t *previousdata = BigBuf_malloc(memoffset); + if (memoffset > 0) { + uint16_t readlen = Flash_ReadData(0, previousdata, memoffset); + if (DBGLEVEL > 1) Dbprintf("[!] Read %u bytes from flash mem", readlen); + } + + // create new bigbuf to hold all data + size_t total_size = memoffset + 4 * auth_attempts; + uint8_t *total_data = BigBuf_malloc(total_size); + + // Add the previousdata array into total_data array + memcpy(total_data, previousdata, memoffset); + + // Copy bytes of capturedPwds immediately following bytes of previousdata + memcpy(total_data + memoffset, capturedPwds, 4 * auth_attempts); + + // Erase first page of flash mem + EraseMemory(); + + // Write total data to flash mem + uint16_t writelen = Flash_WriteData(0, total_data, memoffset + 4 * auth_attempts); + if (DBGLEVEL > 1) Dbprintf("[!] Wrote %u bytes into flash mem", writelen); + + // If pwd saved successfully, blink led A three times + if (writelen > 0) { + SpinErr(0, 200, 5); // blink led A + } + + SpinDelay(100); + + // Reset the SPI Baudrate to the default value (24MHz) + FlashmemSetSpiBaudrate(24000000); + } +} + +void ModInfo(void) { + DbpString(" HF 14a sniff standalone with ULC/ULEV1/NTAG auth storing in flashmem - aka BogitoRun (Bogito)"); +} + +void RunMod() { + + StandAloneMode(); + + Dbprintf(">> Bogiton 14a Sniff UL/UL-EV1/NTAG a.k.a BogitoRun Started <<"); + Dbprintf("Starting to sniff"); + + // param: + // bit 0 - trigger from first card answer + // bit 1 - trigger from first reader 7-bit request + SniffAndStore(0); + LEDsoff(); + SpinDelay(300); + Dbprintf("- [ End ] -> You can take shell back ..."); + Dbprintf("- [ ! ] -> use 'script run read_pwd_mem' to print passwords"); +} diff --git a/armsrc/Standalone/hf_bog.h b/armsrc/Standalone/hf_bog.h new file mode 100644 index 000000000..3dd68b3e2 --- /dev/null +++ b/armsrc/Standalone/hf_bog.h @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// StandAlone Mod +//----------------------------------------------------------------------------- + +#ifndef __HF_BOG_H +#define __HF_BOG_H + +#include "proxmark3.h" +#include "mifareutil.h" +#include "iso14443a.h" +#include "protocols.h" +#include "util.h" +#include "standalone.h" // standalone definitions +#include // for bool +#include +#include +#include "apps.h" +#include "printf.h" +#include "parity.h" + + +#endif /* __HF_BOG_H */ diff --git a/armsrc/Standalone/hf_colin.c b/armsrc/Standalone/hf_colin.c index 1ba31a9c7..76eefcc14 100644 --- a/armsrc/Standalone/hf_colin.c +++ b/armsrc/Standalone/hf_colin.c @@ -1,5 +1,5 @@ //----------------------------------------------------------------------------- -// Colin Brigato, 2016,2017 +// Colin Brigato, 2016, 2017 // Christian Herrmann, 2017 // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -12,47 +12,53 @@ #define MF1KSZ 1024 #define MF1KSZSIZE 64 -//#define FALSE false -//#define TRUE true #define AUTHENTICATION_TIMEOUT 848 uint8_t cjuid[10]; uint32_t cjcuid; +iso14a_card_select_t p_card; int currline; int currfline; int curlline; // TODO : Implement fast read of KEYS like in RFIdea -// als ohttp://ext.delaat.net/rp/2015-2016/p04/report.pdf +// also http://ext.delaat.net/rp/2015-2016/p04/report.pdf // Colin's VIGIKPWN sniff/simulate/clone repeat routine for HF Mifare -void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug) { - uint32_t chunksize = (USB_CMD_DATA_SIZE / 4); +/* +void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug) +{ + uint32_t chunksize = (PM3_CMD_DATA_SIZE / 4); uint8_t totalchunks = len / chunksize; uint8_t last_chunksize = len - (totalchunks * chunksize); char chunk[chunksize + 1]; memset(chunk, 0x00, sizeof(chunk)); - if (debug > 0) { + if (debug > 0) + { Dbprintf("len : %d", len); Dbprintf("chunksize : %d bytes", chunksize); Dbprintf("totalchunks : %d", totalchunks); Dbprintf("last_chunksize: %d", last_chunksize); } - for (uint8_t i = 0; i < totalchunks; i++) { + for (uint8_t i = 0; i < totalchunks; i++) + { memset(chunk, 0x00, sizeof(chunk)); memcpy(chunk, &bigar[i * chunksize], chunksize); DbprintfEx(FLAG_RAWPRINT, "%s", chunk); } - if (last_chunksize > 0) { + if (last_chunksize > 0) + { memset(chunk, 0x00, sizeof(chunk)); memcpy(chunk, &bigar[totalchunks * chunksize], last_chunksize); DbprintfEx(FLAG_RAWPRINT, "%s", chunk); } - if (newlines > 0) { - DbprintfEx(FLAG_NOLOG, " "); + if (newlines > 0) + { + DbprintfEx(FLAG_NEWLINE, " "); } } +*/ void cjSetCursFRight() { vtsend_cursor_position(NULL, 98, (currfline)); @@ -71,65 +77,183 @@ void cjSetCursLeft() { void cjTabulize() { DbprintfEx(FLAG_RAWPRINT, "\t\t\t"); } +/* void cjPrintKey(uint64_t key, uint8_t *foundKey, uint16_t sectorNo, uint8_t type) { char tosendkey[13]; sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[0], foundKey[1], foundKey[2], foundKey[3], foundKey[4], foundKey[5]); cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x | KEY : %s | TYP: %d", sectorNo, tosendkey, type); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x | KEY : %s | TYP: %d", sectorNo, tosendkey, type); +} +*/ + +void ReadLastTagFromFlash() { + SpinOff(0); + LED_A_ON(); + LED_B_ON(); + LED_C_ON(); + LED_D_ON(); + uint32_t startidx = 0; + uint16_t len = 1024; + + DbprintfEx(FLAG_NEWLINE, "Button HELD ! Using LAST Known TAG for Simulation..."); + cjSetCursLeft(); + + size_t size = len; + uint8_t *mem = BigBuf_malloc(size); + + if (!FlashInit()) { + return; + } + Flash_CheckBusy(BUSY_TIMEOUT); + + uint32_t start_time = GetTickCount(); + uint32_t delta_time = 0; + + for (size_t i = 0; i < len; i += size) { + len = MIN((len - i), size); + uint16_t isok = Flash_ReadDataCont(startidx + i, mem, len); + if (isok == len) { + emlSetMem(mem, 0, 64); + } else { + DbprintfEx(FLAG_NEWLINE, "FlashMem reading failed | %d | %d", len, isok); + cjSetCursLeft(); + FlashStop(); + SpinOff(100); + return; + } + } + delta_time = GetTickCountDelta(start_time); + DbprintfEx(FLAG_NEWLINE, "[OK] Last tag recovered from FLASHMEM set to emulator"); + cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%s[IN]%s %s%dms%s for TAG_FLASH_READ", _XGREEN_, _XWHITE_, _XYELLOW_, delta_time, _XWHITE_); + cjSetCursLeft(); + FlashStop(); + SpinOff(0); + return; +} + +void WriteTagToFlash(uint8_t index, size_t size) { + SpinOff(0); + LED_A_ON(); + LED_B_ON(); + LED_C_ON(); + LED_D_ON(); + + uint32_t len = size; + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = len; + + uint8_t data[(size * (16 * 64)) / 1024]; + uint8_t buff[PAGESIZE]; + + emlGetMem(data, 0, (size * 64) / 1024); + + if (!FlashInit()) { + return; + } + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase4k(0, 0); + + uint32_t start_time = GetTickCount(); + uint32_t delta_time = 0; + + while (bytes_remaining > 0) { + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + + uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + memcpy(buff, data + bytes_sent, bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + uint16_t res = Flash_WriteDataCont(bytes_sent + (index * size), buff, bytes_in_packet); + bytes_sent += bytes_in_packet; + + uint8_t isok = (res == bytes_in_packet) ? 1 : 0; + + if (!isok) { + DbprintfEx(FLAG_NEWLINE, "FlashMem write FAILEd [offset %u]", bytes_sent); + cjSetCursLeft(); + SpinOff(100); + return; + } + + LED_A_INV(); + LED_B_INV(); + LED_C_INV(); + LED_D_INV(); + } + delta_time = GetTickCountDelta(start_time); + + DbprintfEx(FLAG_NEWLINE, "[OK] TAG WRITTEN TO FLASH ! [0-to offset %u]", bytes_sent); + cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%s[IN]%s %s%dms%s for TAG_FLASH_WRITE", _XGREEN_, _XWHITE_, _XYELLOW_, delta_time, _XWHITE_); + cjSetCursLeft(); + FlashStop(); + SpinOff(0); + return; +} + +void ModInfo(void) { + DbpString(" HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN (Colin Brigato)"); } void RunMod() { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + currline = 20; curlline = 20; currfline = 24; memset(cjuid, 0, sizeof(cjuid)); cjcuid = 0; - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); uint8_t sectorsCnt = (MF1KSZ / MF1KSZSIZE); uint64_t key64; // Defines current key - uint8_t *keyBlock = NULL; // Where the keys will be held in memory. + uint8_t *keyBlock; // Where the keys will be held in memory. -/* VIGIK EXPIRED DUMP FOR STUDY -Sector 0 -121C7F730208040001FA33F5CB2D021D -44001049164916491649000000000000 -00000000000000000000000000000000 -A0A1A2A3A4A579678800010203040506 -Sector 1 -0F000000000000000000000000000000 -AA0700002102080000740C110600AF13 -000000000000000001740C1108220000 -314B4947495679678800010203040506 -Sector 2 -24E572B923A3D243B402D60CAB576956 -216D6501FC8618B6C426762511AC2DEE -25BF4CEC3618D0BAB3A6E9210D887746 -314B4947495679678800010203040506 -Sector 3 -0FBC41A5D95398E76A1B2029E8EA9735 -088BA2CE732653D0C1147596AFCF94D7 -77B4D91F0442182273A29DEAF7A2D095 -314B4947495679678800010203040506 -Sector 4 -4CEE715866E508CDBC95C640EC9D1E58 -E800457CF8B079414E1B45DD3E6C9317 -77B4D91F0442182273A29DEAF7A2D095 -314B4947495679678800010203040506 -010203040506 0 -Sector 5-0F -00000000000000000000000000000000 -00000000000000000000000000000000 -00000000000000000000000000000000 -FFFFFFFFFFFFFF078069FFFFFFFFFFFF -KEY A : 1KGIV ; -ACCBITS : 796788[00]+VALUE -*/ + /* VIGIK EXPIRED DUMP FOR STUDY + Sector 0 + 121C7F730208040001FA33F5CB2D021D + 44001049164916491649000000000000 + 00000000000000000000000000000000 + A0A1A2A3A4A579678800010203040506 + Sector 1 + 0F000000000000000000000000000000 + AA0700002102080000740C110600AF13 + 000000000000000001740C1108220000 + 314B4947495679678800010203040506 + Sector 2 + 24E572B923A3D243B402D60CAB576956 + 216D6501FC8618B6C426762511AC2DEE + 25BF4CEC3618D0BAB3A6E9210D887746 + 314B4947495679678800010203040506 + Sector 3 + 0FBC41A5D95398E76A1B2029E8EA9735 + 088BA2CE732653D0C1147596AFCF94D7 + 77B4D91F0442182273A29DEAF7A2D095 + 314B4947495679678800010203040506 + Sector 4 + 4CEE715866E508CDBC95C640EC9D1E58 + E800457CF8B079414E1B45DD3E6C9317 + 77B4D91F0442182273A29DEAF7A2D095 + 314B4947495679678800010203040506 + 010203040506 0 + Sector 5-0F + 00000000000000000000000000000000 + 00000000000000000000000000000000 + 00000000000000000000000000000000 + FFFFFFFFFFFFFF078069FFFFFFFFFFFF + KEY A : 1KGIV ; + ACCBITS : 796788[00]+VALUE + */ -//---------------------------- -// Set of keys to be used. -// This should cover ~98% of -// French VIGIK system @2017 -//---------------------------- + //---------------------------- + // Set of keys to be used. + // This should cover ~98% of + // French VIGIK system @2017 + //---------------------------- #define STKEYS 37 @@ -185,12 +309,14 @@ ACCBITS : 796788[00]+VALUE // and why not a simple memset abuse to 0xffize the whole space in one go ? // uint8_t foundKey[2][40][6]; //= [ {0xff} ]; /* C99 abusal 6.7.8.21 uint8_t foundKey[2][40][6]; - for (uint16_t t = 0; t < 2; t++) { + for (uint16_t i = 0; i < 2; i++) { for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - // validKey[t][sectorNo] = false; - for (uint16_t i = 0; i < 6; i++) { - foundKey[t][sectorNo][i] = 0xff; - } + foundKey[i][sectorNo][0] = 0xFF; + foundKey[i][sectorNo][1] = 0xFF; + foundKey[i][sectorNo][2] = 0xFF; + foundKey[i][sectorNo][3] = 0xFF; + foundKey[i][sectorNo][4] = 0xFF; + foundKey[i][sectorNo][5] = 0xFF; } } @@ -200,18 +326,12 @@ ACCBITS : 796788[00]+VALUE bool allKeysFound = true; uint32_t size = mfKeysCnt; - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); - LED_A_ON(); // banner: vtsend_reset(NULL); - DbprintfEx(FLAG_NOLOG, "\r\n%s", clearTerm); - cjPrintBigArray(LOGO, sizeof(LOGO), 0, 0); - DbprintfEx(FLAG_NOLOG, "%s%s%s", _CYAN_, sub_banner, _WHITE_); - DbprintfEx(FLAG_NOLOG, "%s>>%s C.J.B's MifareFastPwn Started\r\n", _RED_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "\r\n%s", clearTerm); + DbprintfEx(FLAG_NEWLINE, "%s%s%s", _XCYAN_, sub_banner, _XWHITE_); + DbprintfEx(FLAG_NEWLINE, "%s>>%s C.J.B's MifareFastPwn Started\r\n", _XRED_, _XWHITE_); currline = 20; curlline = 20; @@ -219,41 +339,63 @@ ACCBITS : 796788[00]+VALUE cjSetCursLeft(); failtag: + vtsend_cursor_position_save(NULL); vtsend_set_attribute(NULL, 1); vtsend_set_attribute(NULL, 5); - DbprintfEx(FLAG_NOLOG, "\t\t\t[ Waiting For Tag ]"); + DbprintfEx(FLAG_NEWLINE, "\t\t\t[ Waiting For Tag ]"); vtsend_set_attribute(NULL, 0); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - while (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) { + SpinOff(50); + LED_A_ON(); + uint8_t ticker = 0; + //while (!BUTTON_PRESS() && !iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) + while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { WDT_HIT(); + + ticker++; + if (ticker % 64 == 0) { + LED_A_INV(); + } + + if (BUTTON_HELD(10) > 0) { + WDT_HIT(); + DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]"); + ReadLastTagFromFlash(); + goto readysim; + } } + + SpinOff(50); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); vtsend_cursor_position_restore(NULL); - DbprintfEx(FLAG_NOLOG, "\t\t\t%s[ GOT a Tag ! ]%s", _GREEN_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "\t\t\t%s[ GOT a Tag ! ]%s", _XGREEN_, _XWHITE_); cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "\t\t\t `---> Breaking keys ---->"); + DbprintfEx(FLAG_NEWLINE, "\t\t\t `---> Breaking keys ---->"); cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "\t%sGOT TAG :%s %08x%s", _RED_, _CYAN_, cjcuid, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "\t%sGOT TAG :%s %08x%s", _XRED_, _XCYAN_, cjcuid, _XWHITE_); if (cjcuid == 0) { cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "%s>>%s BUG: 0000_CJCUID! Retrying...", _RED_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%s>>%s BUG: 0000_CJCUID! Retrying...", _XRED_, _XWHITE_); + SpinErr(0, 100, 8); goto failtag; } - cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "--------+--------------------+-------"); - cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, " SECTOR | KEY | A/B "); - cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "--------+--------------------+-------"); - uint32_t end_time; - uint32_t start_time = end_time = GetTickCount(); + SpinOff(50); + LED_B_ON(); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "--------+--------------------+-------"); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, " SECTOR | KEY | A/B "); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "--------+--------------------+-------"); + + uint32_t start_time = GetTickCount(); + uint32_t delta_time = 0; //--------------------------------------------------------------------------- // WE SHOULD FIND A WAY TO GET UID TO AVOID THIS "TESTRUN" @@ -286,250 +428,262 @@ failtag: for (uint8_t type = 0; type < 2 && !err && !trapped; type++) { for (int sec = 0; sec < sectorsCnt && !err && !trapped; ++sec) { key = cjat91_saMifareChkKeys(sec * 4, type, NULL, size, &keyBlock[0], &key64); - // key = saMifareChkKeys(sec * 4, type, NULL, size, &keyBlock[0], &key64); + if (key == -1) { err = 1; allKeysFound = false; // used in “portable†imlementation on microcontroller: it reports back the fail and open the standalone lock - // cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); + // reply_old(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); break; } else if (key == -2) { err = 1; // Can't select card. allKeysFound = false; - // cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); + // reply_old(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); break; } else { /* BRACE YOURSELF : AS LONG AS WE TRAP A KNOWN KEY, WE STOP CHECKING AND ENFORCE KNOWN SCHEMES */ - // uint8_t tosendkey[12]; + // uint8_t tosendkey[13]; char tosendkey[13]; num_to_bytes(key64, 6, foundKey[type][sec]); cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %012" PRIx64 " ; TYP: %i", sec, key64, type); - /*cmd_send(CMD_CJB_INFORM_CLIENT_KEY, 12, sec, type, tosendkey, 12);*/ - + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %012" PRIx64 " ; TYP: %i", sec, key64, type); + /*reply_old(CMD_CJB_INFORM_CLIENT_KEY, 12, sec, type, tosendkey, 12);*/ switch (key64) { - ///////////////////////////////////////////////////////// - // COMMON SCHEME 1 : INFINITRON/HEXACT - case 0x484558414354: - cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_); - cjSetCursLeft(); + ///////////////////////////////////////////////////////// + // COMMON SCHEME 1 : INFINITRON/HEXACT + case 0x484558414354: + cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _XRED_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, " .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, " .TAG SEEMS %sDETERMINISTIC%s. ", _XGREEN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%sDetected: %s INFI_HEXACT_VIGIK_TAG%s", _ORANGE_, _CYAN_, _WHITE_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%sDetected: %s INFI_HEXACT_VIGIK_TAG%s", _XORANGE_, _XCYAN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "...%s[%sKey_derivation_schemeTest%s]%s...", _XYELLOW_, _XGREEN_, _XYELLOW_, _XGREEN_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_); - ; - // Type 0 / A first - uint16_t t = 0; - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _XGREEN_, _XWHITE_); + ; + // Type 0 / A first + uint16_t t = 0; + for (uint16_t s = 0; s < sectorsCnt; s++) { + num_to_bytes(0x484558414354, 6, foundKey[t][s]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][s][0], foundKey[t][s][1], foundKey[t][s][2], + foundKey[t][s][3], foundKey[t][s][4], foundKey[t][s][5]); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", s, tosendkey, t); + } + t = 1; + uint16_t sectorNo = 0; + num_to_bytes(0xa22ae129c013, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 1; + num_to_bytes(0x49fae4e3849f, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 2; + num_to_bytes(0x38fcf33072e0, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 3; + num_to_bytes(0x8ad5517b4b18, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 4; + num_to_bytes(0x509359f131b1, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 5; + num_to_bytes(0x6c78928e1317, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 6; + num_to_bytes(0xaa0720018738, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 7; + num_to_bytes(0xa6cac2886412, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 8; + num_to_bytes(0x62d0c424ed8e, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 9; + num_to_bytes(0xe64a986a5d94, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 10; + num_to_bytes(0x8fa1d601d0a2, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 11; + num_to_bytes(0x89347350bd36, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 12; + num_to_bytes(0x66d2b7dc39ef, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 13; + num_to_bytes(0x6bc1e1ae547d, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 14; + num_to_bytes(0x22729a9bd40f, 6, foundKey[t][sectorNo]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], + foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); + cjSetCursRight(); + + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + sectorNo = 15; num_to_bytes(0x484558414354, 6, foundKey[t][sectorNo]); sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - } - t = 1; - uint16_t sectorNo = 0; - num_to_bytes(0xa22ae129c013, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 1; - num_to_bytes(0x49fae4e3849f, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + trapped = 1; + break; + ////////////////END OF SCHEME 1////////////////////////////// - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 2; - num_to_bytes(0x38fcf33072e0, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + /////////////////////////////////////// + // COMMON SCHEME 2 : URMET CAPTIVE / COGELEC!/? + case 0x8829da9daf76: + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 3; - num_to_bytes(0x8ad5517b4b18, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _XRED_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 4; - num_to_bytes(0x509359f131b1, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, " .TAG SEEMS %sDETERMINISTIC%s. ", _XGREEN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 5; - num_to_bytes(0x6c78928e1317, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "%sDetected :%sURMET_CAPTIVE_VIGIK_TAG%s", _XORANGE_, _XCYAN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 6; - num_to_bytes(0xaa0720018738, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "...%s[%sKey_derivation_schemeTest%s]%s...", _XYELLOW_, _XGREEN_, _XYELLOW_, _XGREEN_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 7; - num_to_bytes(0xa6cac2886412, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _XGREEN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 8; - num_to_bytes(0x62d0c424ed8e, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 9; - num_to_bytes(0xe64a986a5d94, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 10; - num_to_bytes(0x8fa1d601d0a2, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 11; - num_to_bytes(0x89347350bd36, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 12; - num_to_bytes(0x66d2b7dc39ef, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 13; - num_to_bytes(0x6bc1e1ae547d, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 14; - num_to_bytes(0x22729a9bd40f, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - sectorNo = 15; - num_to_bytes(0x484558414354, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - trapped = 1; - break; - ////////////////END OF SCHEME 1////////////////////////////// - - /////////////////////////////////////// - // COMMON SCHEME 2 : URMET CAPTIVE / COGELEC!/? - case 0x8829da9daf76: - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, " .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "%sDetected :%sURMET_CAPTIVE_VIGIK_TAG%s", _ORANGE_, _CYAN_, _WHITE_); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_); - cjSetCursLeft(); - - // emlClearMem(); - // A very weak one... - for (uint16_t t = 0; t < 2; t++) { - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - num_to_bytes(key64, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); - - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); + // emlClearMem(); + // A very weak one... + for (uint16_t i = 0; i < 2; i++) { + for (uint16_t s = 0; s < sectorsCnt; s++) { + num_to_bytes(key64, 6, foundKey[i][s]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", + foundKey[i][s][0], + foundKey[i][s][1], + foundKey[i][s][2], + foundKey[i][s][3], + foundKey[i][s][4], + foundKey[i][s][5] + ); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", s, tosendkey, i); + } } - } - trapped = 1; - break; - ////////////////END OF SCHEME 2////////////////////////////// + trapped = 1; + break; + ////////////////END OF SCHEME 2////////////////////////////// - /////////////////////////////////////// - // COMMON SCHEME 3 : NORALSY "A-LARON & B-LARON . . . NORAL-B & NORAL-A" - case 0x414c41524f4e: // Thumbs up to the guy who had the idea of such a "mnemotechnical" key pair - case 0x424c41524f4e: - cjSetCursLeft(); + /////////////////////////////////////// + // COMMON SCHEME 3 : NORALSY "A-LARON & B-LARON . . . NORAL-B & NORAL-A" + case 0x414c41524f4e: // Thumbs up to the guy who had the idea of such a "mnemotechnical" key pair + case 0x424c41524f4e: + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _XRED_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, " .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, " .TAG SEEMS %sDETERMINISTIC%s. ", _XGREEN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s Detected :%sNORALSY_VIGIK_TAG %s", _ORANGE_, _CYAN_, _WHITE_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "%s Detected :%sNORALSY_VIGIK_TAG %s", _XORANGE_, _XCYAN_, _XWHITE_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_); - cjSetCursLeft(); + DbprintfEx(FLAG_NEWLINE, "...%s[%sKey_derivation_schemeTest%s]%s...", _XYELLOW_, _XGREEN_, _XYELLOW_, _XGREEN_); + cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_); - ; - t = 0; - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - num_to_bytes(0x414c41524f4e, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _XGREEN_, _XWHITE_); - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - ; - } - t = 1; - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - num_to_bytes(0x424c41524f4e, 6, foundKey[t][sectorNo]); - sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2], - foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]); - cjSetCursRight(); + t = 0; + for (uint16_t s = 0; s < sectorsCnt; s++) { + num_to_bytes(0x414c41524f4e, 6, foundKey[t][s]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", + foundKey[t][s][0], + foundKey[t][s][1], + foundKey[t][s][2], + foundKey[t][s][3], + foundKey[t][s][4], + foundKey[t][s][5]); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", s, tosendkey, t); + } - DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t); - } - trapped = 1; - break; - ////////////////END OF SCHEME 3////////////////////////////// + t = 1; + for (uint16_t s = 0; s < sectorsCnt; s++) { + num_to_bytes(0x424c41524f4e, 6, foundKey[t][s]); + sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", + foundKey[t][s][0], + foundKey[t][s][1], + foundKey[t][s][2], + foundKey[t][s][3], + foundKey[t][s][4], + foundKey[t][s][5]); + cjSetCursRight(); + DbprintfEx(FLAG_NEWLINE, "SEC: %02x ; KEY : %s ; TYP: %d", s, tosendkey, t); + } + trapped = 1; + break; + ////////////////END OF SCHEME 3////////////////////////////// } /* etc etc for testing schemes quick schemes */ } @@ -537,11 +691,12 @@ failtag: } if (!allKeysFound) { - // cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); cjSetCursLeft(); cjTabulize(); - DbprintfEx(FLAG_NOLOG, "%s[ FAIL ]%s\r\n->did not found all the keys :'(", _RED_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%s[ FAIL ]%s\r\n->did not found all the keys :'(", _XRED_, _XWHITE_); cjSetCursLeft(); + SpinErr(1, 100, 8); + SpinOff(100); return; } @@ -557,102 +712,113 @@ failtag: } cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>%s Setting Keys->Emulator MEM...[%sOK%s]", _YELLOW_, _WHITE_, _GREEN_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%s>>%s Setting Keys->Emulator MEM...[%sOK%s]", _XYELLOW_, _XWHITE_, _XGREEN_, _XWHITE_); /* filling TAG to emulator */ - uint8_t filled = 0; + int filled; cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>%s Filling Emulator <- from A keys...", _YELLOW_, _WHITE_); - e_MifareECardLoad(sectorsCnt, 0, 0, &filled); - if (filled != 1) { + DbprintfEx(FLAG_NEWLINE, "%s>>%s Filling Emulator <- from A keys...", _XYELLOW_, _XWHITE_); + filled = e_MifareECardLoad(sectorsCnt, 0); + if (filled != PM3_SUCCESS) { cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>%s W_FAILURE ! %sTrying fallback B keys....", _RED_, _ORANGE_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%s>>%s W_FAILURE ! %sTrying fallback B keys....", _XRED_, _XORANGE_, _XWHITE_); /* no trace, no dbg */ - e_MifareECardLoad(sectorsCnt, 1, 0, &filled); - if (filled != 1) { + filled = e_MifareECardLoad(sectorsCnt, 1); + if (filled != PM3_SUCCESS) { cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "FATAL:EML_FALLBACKFILL_B"); - // cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); + DbprintfEx(FLAG_NEWLINE, "FATAL:EML_FALLBACKFILL_B"); + SpinErr(2, 100, 8); + SpinOff(100); return; } } - end_time = GetTickCount(); + + delta_time = GetTickCountDelta(start_time); cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%s>>%s Time for VIGIK break :%s%dms%s", _GREEN_, _WHITE_, _YELLOW_, end_time - start_time, _WHITE_); - // cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0); - - // SIM ? - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "-> We launch Emulation ->"); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "%s!> HOLD ON : %s When you'll click, simm will stop", _RED_, _WHITE_); - cjSetCursLeft(); - - DbprintfEx(FLAG_NOLOG, "Then %s immediately %s we'll try to %s dump our emulator state%s \r\nin a %s chinese tag%s", _RED_, _WHITE_, _YELLOW_, _WHITE_, - _CYAN_, _WHITE_); - cjSetCursLeft(); - cjSetCursLeft(); - - cjTabulize(); + DbprintfEx(FLAG_NEWLINE, "%s>>%s Time for VIGIK break :%s%dms%s", _XGREEN_, _XWHITE_, _XYELLOW_, delta_time, _XWHITE_); vtsend_cursor_position_save(NULL); vtsend_set_attribute(NULL, 1); vtsend_set_attribute(NULL, 5); - DbprintfEx(FLAG_NOLOG, "[ SIMULATION ]"); - vtsend_set_attribute(NULL, 0); - Mifare1ksim((FLAG_4B_UID_IN_DATA | FLAG_UID_IN_EMUL ), 0, 0, cjuid); - vtsend_cursor_position_restore(NULL); - DbprintfEx(FLAG_NOLOG, "[ SIMUL ENDED ]%s", _GREEN_, _WHITE_); + cjTabulize(); + DbprintfEx(FLAG_NEWLINE, "[ WRITING FLASH ]"); + cjSetCursLeft(); cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "<- We're out of Emulation"); + WriteTagToFlash(0, 1024); + +readysim: + // SIM ? + cjSetCursLeft(); + + DbprintfEx(FLAG_NEWLINE, "-> We launch Emulation ->"); + cjSetCursLeft(); + + DbprintfEx(FLAG_NEWLINE, "%s!> HOLD ON : %s When you'll click, simm will stop", _XRED_, _XWHITE_); + cjSetCursLeft(); + + DbprintfEx(FLAG_NEWLINE, "Then %s immediately %s we'll try to %s dump our emulator state%s \r\nin a %s chinese tag%s", _XRED_, _XWHITE_, _XYELLOW_, _XWHITE_, + _XCYAN_, _XWHITE_); + cjSetCursLeft(); + cjSetCursLeft(); + + cjTabulize(); + + DbprintfEx(FLAG_NEWLINE, "[ SIMULATION ]"); + vtsend_set_attribute(NULL, 0); + + SpinOff(100); + LED_C_ON(); + + uint16_t flags; + switch (p_card.uidlen) { + case 10: + flags = FLAG_10B_UID_IN_DATA; + break; + case 7: + flags = FLAG_7B_UID_IN_DATA; + break; + default: + flags = FLAG_4B_UID_IN_DATA; + break; + } + Mifare1ksim(flags | FLAG_MF_1K, 0, cjuid); + LED_C_OFF(); + SpinOff(50); + vtsend_cursor_position_restore(NULL); + DbprintfEx(FLAG_NEWLINE, "[ SIMUL ENDED ]%s", _XGREEN_, _XWHITE_); + cjSetCursLeft(); + + DbprintfEx(FLAG_NEWLINE, "<- We're out of Emulation"); // END SIM - /*for (;;) { - WDT_HIT(); - - int button_action = BUTTON_HELD(500); - if (button_action == 0) { // No button action, proceed with sim - SpinDelay(100); - WDT_HIT(); - - } else if (button_action == BUTTON_SINGLE_CLICK) { - */ cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "-> Trying a clone !"); + DbprintfEx(FLAG_NEWLINE, "-> Trying a clone !"); saMifareMakeTag(); cjSetCursLeft(); vtsend_cursor_position_restore(NULL); - DbprintfEx(FLAG_NOLOG, "%s[ CLONED? ]", _CYAN_); + DbprintfEx(FLAG_NEWLINE, "%s[ CLONED? ]", _XCYAN_); - DbprintfEx(FLAG_NOLOG, "-> End Cloning."); + DbprintfEx(FLAG_NEWLINE, "-> End Cloning."); WDT_HIT(); - // break; - /*} else if (button_action == BUTTON_HOLD) { - DbprintfEx(FLAG_RAWPRINT,"Playtime over. Begin cloning..."); - iGotoClone = 1; - break; - }*/ - // Debunk... - // SpinDelay(300); cjSetCursLeft(); cjTabulize(); vtsend_set_attribute(NULL, 0); vtsend_set_attribute(NULL, 7); - DbprintfEx(FLAG_NOLOG, "- [ LA FIN ] -\r\n%s`-> You can take shell back :) ...", _WHITE_); + DbprintfEx(FLAG_NEWLINE, "- [ LA FIN ] -\r\n%s`-> You can take shell back :) ...", _XWHITE_); cjSetCursLeft(); vtsend_set_attribute(NULL, 0); - + SpinErr(3, 100, 16); + SpinDown(75); + SpinOff(100); return; } @@ -660,117 +826,100 @@ failtag: * - *datain used as error return * - tracing is falsed */ -void e_MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - MF_DBGLEVEL = MF_DBG_NONE; +int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype) { + DBGLEVEL = DBG_NONE; + + uint8_t numSectors = numofsectors; + uint8_t keyType = keytype; - uint8_t numSectors = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - // uint32_t cuid; struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - byte_t dataoutbuf[16]; - byte_t dataoutbuf2[16]; - // uint8_t uid[10]; + uint8_t dataoutbuf[16]; + uint8_t dataoutbuf2[16]; - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); set_tracing(false); bool isOK = true; - // iso14443a_fast_select_card(cjuid, 0); - if (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) { + if (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { isOK = false; - if (MF_DBGLEVEL >= 1) + if (DBGLEVEL >= 1) DbprintfEx(FLAG_RAWPRINT, "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, cjcuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { - isOK = false; - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Sector[%2d]. Auth error", sectorNo); + for (uint8_t s = 0; isOK && s < numSectors; s++) { + uint64_t ui64Key = emlGetKey(s, keyType); + if (s == 0) { + if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(s), keyType, ui64Key, AUTH_FIRST)) { + + if (DBGLEVEL >= 1) + DbprintfEx(FLAG_NEWLINE, "Sector[%2d]. Auth error", s); break; } } else { - if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { + if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(s), keyType, ui64Key, AUTH_NESTED)) { isOK = false; - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Sector[%2d]. Auth nested error", sectorNo); + if (DBGLEVEL >= 1) + DbprintfEx(FLAG_NEWLINE, "Sector[%2d]. Auth nested error", s); break; } } - for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { - if (isOK && mifare_classic_readblock(pcs, cjcuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { + for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(s); blockNo++) { + if (isOK && mifare_classic_readblock(pcs, cjcuid, FirstBlockOfSector(s) + blockNo, dataoutbuf)) { isOK = false; - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Error reading sector %2d block %2d", sectorNo, blockNo); + if (DBGLEVEL >= 1) + DbprintfEx(FLAG_NEWLINE, "Error reading sector %2d block %2d", s, blockNo); break; }; if (isOK) { - *datain = 1; - 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); + if (blockNo < NumBlocksPerSector(s) - 1) { + emlSetMem(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1); + } else { + // sector trailer, keep the keys, set only the AC + emlGetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1); memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); - emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); + emlSetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1); } - } else { - *datain = 0; } } } if (mifare_classic_halt(pcs, cjcuid)) { - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Halt error"); + if (DBGLEVEL >= 1) + DbprintfEx(FLAG_NEWLINE, "Halt error"); }; - // ----------------------------- crypto1 destroy crypto1_destroy(pcs); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - if (MF_DBGLEVEL >= 2) - DbpString("EMUL FILL SECTORS FINISHED\n"); + return (isOK) ? PM3_SUCCESS : PM3_EUNDEF; } -/* . . . */ - /* the chk function is a piwi’ed(tm) check that will try all keys for a particular sector. also no tracing no dbg */ - int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key) { - MF_DBGLEVEL = MF_DBG_NONE; + DBGLEVEL = DBG_NONE; iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); set_tracing(false); - // uint8_t uid[10]; - // uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - // byte_t isOK = 0; for (int i = 0; i < keyCount; ++i) { - LEDsoff(); /* no need for anticollision. just verify tag is still here */ // if (!iso14443a_fast_select_card(cjuid, 0)) { - if (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) { + if (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "%sFATAL%s : E_MF_LOSTTAG", _RED_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%sFATAL%s : E_MF_LOSTTAG", _XRED_, _XWHITE_); return -1; } @@ -782,13 +931,11 @@ int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, ui SpinDelayUs(AUTHENTICATION_TIMEOUT); continue; } - LED_A_ON(); crypto1_destroy(pcs); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); *key = ui64Key; return i; } - LED_A_ON(); crypto1_destroy(pcs); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -796,19 +943,18 @@ int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, ui } void saMifareMakeTag(void) { - // uint8_t cfail = 0;` + uint8_t cfail = 0; cjSetCursLeft(); cjTabulize(); vtsend_cursor_position_save(NULL); vtsend_set_attribute(NULL, 1); - DbprintfEx(FLAG_NOLOG, "[ CLONING ]"); + DbprintfEx(FLAG_NEWLINE, "[ CLONING ]"); vtsend_set_attribute(NULL, 0); cjSetCursFRight(); - DbprintfEx(FLAG_NOLOG, ">> Write to Special:"); + DbprintfEx(FLAG_NEWLINE, ">> Write to Special:"); int flags = 0; - LED_A_ON(); // yellow for (int blockNum = 0; blockNum < 16 * 4; blockNum++) { uint8_t mblock[16]; // cnt = 0; @@ -825,13 +971,14 @@ void saMifareMakeTag(void) { if (blockNum == 16 * 4 - 1) flags = 0x04 + 0x10; - if (saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock)) { //&& cnt <= retry) { - // cnt++; + if (saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock)) { + //&& cnt <= retry) { + // cnt++; cjSetCursFRight(); if (currfline > 53) { currfline = 54; } - DbprintfEx(FLAG_NOLOG, "Block :%02x %sOK%s", blockNum, _GREEN_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "Block :%02x %sOK%s", blockNum, _XGREEN_, _XWHITE_); // DbprintfEx(FLAG_RAWPRINT,"FATAL:E_MF_CHINESECOOK_NORICE"); // cfail=1; // return; @@ -840,21 +987,26 @@ void saMifareMakeTag(void) { cjSetCursLeft(); cjSetCursLeft(); - DbprintfEx(FLAG_NOLOG, "`--> %sFAIL%s : CHN_FAIL_BLK_%02x_NOK", _RED_, _WHITE_, blockNum); + DbprintfEx(FLAG_NEWLINE, "`--> %sFAIL%s : CHN_FAIL_BLK_%02x_NOK", _XRED_, _XWHITE_, blockNum); cjSetCursFRight(); - DbprintfEx(FLAG_NOLOG, "%s>>>>%s STOP AT %02x", _RED_, _WHITE_, blockNum); - + DbprintfEx(FLAG_NEWLINE, "%s>>>>%s STOP AT %02x", _XRED_, _XWHITE_, blockNum); + cfail++; break; } cjSetCursFRight(); - DbprintfEx(FLAG_NOLOG, "%s>>>>>>>> END <<<<<<<<%s", _YELLOW_, _WHITE_); + DbprintfEx(FLAG_NEWLINE, "%s>>>>>>>> END <<<<<<<<%s", _XYELLOW_, _XWHITE_); // break; /*if (cfail == 1) { DbprintfEx(FLAG_RAWPRINT,"FATAL: E_MF_HARA_KIRI_\r\n"); break; } */ } + if (cfail == 0) { + SpinUp(50); + SpinUp(50); + SpinUp(50); + } } //----------------------------------------------------------------------------- @@ -862,7 +1014,6 @@ void saMifareMakeTag(void) { // Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) //----------------------------------------------------------------------------- int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - // params uint8_t needWipe = arg0; // bit 0 - need get UID @@ -879,41 +1030,31 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data uint8_t wipeC[] = {0x41}; // variables - byte_t isOK = 0; - // uint8_t uid[10] = {0x00}; + uint8_t isOK = 0; uint8_t d_block[18] = {0x00}; - // uint32_t cuid; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; // reset FPGA and LED if (workFlags & 0x08) { - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - // clear_trace(); set_tracing(FALSE); } while (true) { - // cjSetCursLeft(); + cjSetCursLeft(); // get UID from chip if (workFlags & 0x01) { - // if (!iso14443a_fast_select_card(cjuid, 0)) { - - if (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Can't select card"); + if (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { + DbprintfEx(FLAG_NEWLINE, "Can't select card"); break; }; if (mifare_classic_halt(NULL, cjcuid)) { - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Halt error"); + DbprintfEx(FLAG_NEWLINE, "Halt error"); break; }; }; @@ -922,21 +1063,18 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data if (needWipe) { ReaderTransmitBitsPar(wupC1, 7, 0, NULL); if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - // if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "wupC1 error"); + DbprintfEx(FLAG_NEWLINE, "wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "wipeC error"); + DbprintfEx(FLAG_NEWLINE, "wipeC error"); break; }; if (mifare_classic_halt(NULL, cjcuid)) { - if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "Halt error"); + DbprintfEx(FLAG_NEWLINE, "Halt error"); break; }; }; @@ -946,40 +1084,35 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1, 7, 0, NULL); if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - // if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "wupC1 error"); + DbprintfEx(FLAG_NEWLINE, "wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - // if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "wupC2 errorv"); + DbprintfEx(FLAG_NEWLINE, "wupC2 errorv"); break; }; } if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - // if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "write block send command error"); + DbprintfEx(FLAG_NEWLINE, "write block send command error"); break; }; memcpy(d_block, datain, 16); - AddCrc14A(d_block,16); + AddCrc14A(d_block, 16); ReaderTransmit(d_block, sizeof(d_block), NULL); if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - // if (MF_DBGLEVEL >= 1) - DbprintfEx(FLAG_NOLOG, "write block send data error"); + DbprintfEx(FLAG_NEWLINE, "write block send data error"); break; }; if (workFlags & 0x04) { if (mifare_classic_halt(NULL, cjcuid)) { - // if (MF_DBGLEVEL >= 1) cjSetCursFRight(); - DbprintfEx(FLAG_NOLOG, "Halt error"); + DbprintfEx(FLAG_NEWLINE, "Halt error"); break; }; } @@ -990,10 +1123,7 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data if ((workFlags & 0x10) || (!isOK)) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); } return isOK; } - - diff --git a/armsrc/Standalone/hf_colin.h b/armsrc/Standalone/hf_colin.h index 83c152095..8c8e391e1 100644 --- a/armsrc/Standalone/hf_colin.h +++ b/armsrc/Standalone/hf_colin.h @@ -16,39 +16,44 @@ #ifndef __HF_COLIN_H #define __HF_COLIN_H -#include // for bool -#include -#include -#include "standalone.h" // standalone definitions #include "proxmark3.h" +#include "mifaresim.h" // mifare1ksim #include "mifareutil.h" #include "iso14443a.h" #include "protocols.h" #include "util.h" +#include "standalone.h" // standalone definitions +#include // for bool +#include +#include #include "vtsend.h" #include "apps.h" -#include "usb_cmd.h" // mifare1ksim flags +#include "printf.h" -#define _RED_ "\x1b[31m" -#define _GREEN_ "\x1b[32m" -#define _YELLOW_ "\x1b[33m" -#define _BLUE_ "\x1b[34m" -#define _MAGENTA_ "\x1b[35m" -#define _CYAN_ "\x1b[36m" -#define _WHITE_ "\x1b[0m" -#define _ORANGE_ _YELLOW_ +#define _XRED_ "\x1b[31m" +#define _XGREEN_ "\x1b[32m" +#define _XYELLOW_ "\x1b[33m" +#define _XBLUE_ "\x1b[34m" +#define _XMAGENTA_ "\x1b[35m" +#define _XCYAN_ "\x1b[36m" +#define _XWHITE_ "\x1b[0m" +#define _XORANGE_ _XYELLOW_ int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key); -void e_MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype); void saMifareMakeTag(void); int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug); +void WriteTagToFlash(uint8_t index, size_t size); const char clearTerm[8] = {0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, '\0'}; -#define LOGO logo_kigiv +//void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug); +//void TestFlashmemSpeed(size_t buffersize, uint32_t spibaudrate); -const char sub_banner[] = " From Vigik : \"20 years of (un)security without a single update\""; +//#define LOGO logo_kigiv + +const char sub_banner[] = " From Vigik : \"20 years of (un)security without a single update\""; +/* const char logo_kigiv[] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, @@ -409,8 +414,9 @@ const char logo_kigiv[] = { 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x0d, 0x0a}; unsigned int logo_kigiv_len = 9303; +*/ -const char logo_kigiv_nocolor[] = { +/*const char logo_kigiv_nocolor[] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, @@ -494,6 +500,6 @@ const char logo_kigiv_nocolor[] = { 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x31, 0x0d, 0x0a}; -unsigned int logo_kigiv_nocolor_len = 2153; +unsigned int logo_kigiv_nocolor_len = 2153;*/ #endif /* __HF_COLIN_H */ diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index e83d13a1d..66147c2fb 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -13,7 +13,7 @@ I've personally recoded the image of the ARM in order to automate the attack and simulation on Mifare cards. I've moved some of the implementation on the client side to the ARM such as *chk*, *ecfill*, *sim* -and *clone* commands. +and *clone* commands. ### What it does now: It will check if the keys from the attacked tag are a subset from @@ -35,265 +35,414 @@ on a blank card. #include "hf_mattyrun.h" +uint8_t uid[10]; +uint32_t cuid; +iso14a_card_select_t p_card; + +//----------------------------------------------------------------------------- +// Matt's StandAlone mod. +// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) +//----------------------------------------------------------------------------- +static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + // params + uint8_t needWipe = arg0; + // bit 0 - need get UID + // 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 + uint8_t workFlags = arg1; + uint8_t blockNo = arg2; + + // card commands + uint8_t wupC1[] = {0x40}; + uint8_t wupC2[] = {0x43}; + uint8_t wipeC[] = {0x41}; + + // variables + uint8_t isOK = 0; + uint8_t d_block[18] = {0x00}; + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + + // reset FPGA and LED + if (workFlags & 0x08) { + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + set_tracing(false); + } + + while (true) { + // get UID from chip + if (workFlags & 0x01) { + if (!iso14443a_select_card(uid, &p_card, &cuid, true, 0, true)) { + DbprintfEx(FLAG_NEWLINE, "Can't select card"); + break; + }; + + if (mifare_classic_halt(NULL, cuid)) { + DbprintfEx(FLAG_NEWLINE, "Halt error"); + break; + }; + }; + + // reset chip + if (needWipe) { + ReaderTransmitBitsPar(wupC1, 7, 0, NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "wupC1 error"); + break; + }; + + ReaderTransmit(wipeC, sizeof(wipeC), NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "wipeC error"); + break; + }; + + if (mifare_classic_halt(NULL, cuid)) { + DbprintfEx(FLAG_NEWLINE, "Halt error"); + break; + }; + }; + + // chaud + // write block + if (workFlags & 0x02) { + ReaderTransmitBitsPar(wupC1, 7, 0, NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "wupC1 error"); + break; + }; + + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "wupC2 errorv"); + break; + }; + } + + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "write block send command error"); + break; + }; + + memcpy(d_block, datain, 16); + AddCrc14A(d_block, 16); + ReaderTransmit(d_block, sizeof(d_block), NULL); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { + DbprintfEx(FLAG_NEWLINE, "write block send data error"); + break; + }; + + if (workFlags & 0x04) { + if (mifare_classic_halt(NULL, cuid)) { + DbprintfEx(FLAG_NEWLINE, "Halt error"); + break; + }; + } + + isOK = 1; + break; + } + + if ((workFlags & 0x10) || (!isOK)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + + return isOK; +} + +/* the chk function is a piwi’ed(tm) check that will try all keys for +a particular sector. also no tracing no dbg */ +static int saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key) { + DBGLEVEL = DBG_NONE; + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + set_tracing(false); + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + for (int i = 0; i < keyCount; ++i) { + + /* no need for anticollision. just verify tag is still here */ + // if (!iso14443a_fast_select_card(cjuid, 0)) { + if (!iso14443a_select_card(uid, &p_card, &cuid, true, 0, true)) { + DbprintfEx(FLAG_NEWLINE, "FATAL : E_MF_LOSTTAG"); + return -1; + } + + uint64_t ui64Key = bytes_to_num(datain + i * 6, 6); + if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + uint8_t dummy_answer = 0; + ReaderTransmit(&dummy_answer, 1, NULL); + // wait for the card to become ready again + SpinDelayUs(AUTHENTICATION_TIMEOUT); + continue; + } + crypto1_destroy(pcs); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + *key = ui64Key; + return i; + } + crypto1_destroy(pcs); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + return -1; +} + +void ModInfo(void) { + DbpString(" HF Mifare sniff/clone - aka MattyRun (Matías A. Ré Medina)"); +} + void RunMod() { - StandAloneMode(); - - /* - It will check if the keys from the attacked tag are a subset from - the hardcoded set of keys inside of the ARM. If this is the case - then it will load the keys into the emulator memory and also the - content of the victim tag, to finally simulate it. - - Alternatively, it can be dumped into a blank card. - - This source code has been tested only in Mifare 1k. - - If you're using the proxmark connected to a device that has an OS, and you're not using the proxmark3 client to see the debug - messages, you MUST uncomment usb_disable(). - */ - + StandAloneMode(); + Dbprintf(">> Matty mifare chk/dump/sim a.k.a MattyRun Started <<"); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // usb_disable(); // Comment this line if you want to see debug messages. - /* - Pseudo-configuration block. + It will check if the keys from the attacked tag are a subset from + the hardcoded set of keys inside of the ARM. If this is the case + then it will load the keys into the emulator memory and also the + content of the victim tag, to finally simulate it. + + Alternatively, it can be dumped into a blank card. + + This source code has been tested only in Mifare 1k. + + If you're using the proxmark connected to a device that has an OS, and you're not using the proxmark3 client to see the debug + messages, you MUST uncomment usb_disable(). */ - char keyTypec = '?'; // 'A'/'B' or both keys '?' - bool printKeys = false; // Prints keys - bool transferToEml = true; // Transfer keys to emulator memory - bool ecfill = true; // Fill emulator memory with cards content. - bool simulation = true; // Simulates an exact copy of the target tag - bool fillFromEmulator = false; // Dump emulator memory. + + // Comment this line below if you want to see debug messages. + // usb_disable(); + + /* + Pseudo-configuration block. + */ + bool printKeys = false; // Prints keys + bool transferToEml = true; // Transfer keys to emulator memory + bool simulation = true; // Simulates an exact copy of the target tag + bool fillFromEmulator = false; // Dump emulator memory. - uint16_t mifare_size = 1024; // Mifare 1k (only 1k supported for now) - uint8_t sectorSize = 64; // 1k's sector size is 64 bytes. - uint8_t blockNo = 3; // Security block is number 3 for each sector. - uint8_t sectorsCnt = (mifare_size/sectorSize); - uint8_t keyType; // Keytype buffer - uint64_t key64; // Defines current key - uint8_t *keyBlock = NULL; // Where the keys will be held in memory. - uint8_t stKeyBlock = 20; // Set the quantity of keys in the block. - uint8_t filled = 0; // Used to check if the memory was filled with success. - bool keyFound = false; + uint16_t mifare_size = 1024; // Mifare 1k (only 1k supported for now) + uint8_t sectorSize = 64; // 1k's sector size is 64 bytes. + uint8_t blockNo = 3; // Security block is number 3 for each sector. + uint8_t sectorsCnt = (mifare_size / sectorSize); + uint8_t keyType = 2; // Keytype buffer + uint64_t key64; // Defines current key + uint8_t *keyBlock; // Where the keys will be held in memory. + uint8_t stKeyBlock = 20; // Set the quantity of keys in the block. + bool keyFound = false; - /* - Set of keys to be used. - */ - uint64_t mfKeys[] = { - 0xffffffffffff, // Default key - 0x000000000000, // Blank key - 0xa0a1a2a3a4a5, // NFCForum MAD key - 0xb0b1b2b3b4b5, - 0xaabbccddeeff, - 0x4d3a99c351dd, - 0x1a982c7e459a, - 0xd3f7d3f7d3f7, - 0x714c5c886e97, - 0x587ee5f9350f, - 0xa0478cc39091, - 0x533cb6c723f6, - 0x8fd0a4f256e9, - }; + /* + Set of keys to be used. + */ + uint64_t mfKeys[] = { + 0xffffffffffff, // Default key + 0x000000000000, // Blank key + 0xa0a1a2a3a4a5, // NFCForum MAD key + 0xb0b1b2b3b4b5, + 0xaabbccddeeff, + 0x4d3a99c351dd, + 0x1a982c7e459a, + 0xd3f7d3f7d3f7, + 0x714c5c886e97, + 0x587ee5f9350f, + 0xa0478cc39091, + 0x533cb6c723f6, + 0x8fd0a4f256e9, + }; - /* - This part allocates the byte representation of the - keys in keyBlock's memory space . - */ - keyBlock = BigBuf_malloc(stKeyBlock * 6); - int mfKeysCnt = sizeof(mfKeys) / sizeof(uint64_t); + /* + This part allocates the byte representation of the + keys in keyBlock's memory space . + */ + keyBlock = BigBuf_malloc(stKeyBlock * 6); + int mfKeysCnt = sizeof(mfKeys) / sizeof(uint64_t); - for (int mfKeyCounter = 0; mfKeyCounter < mfKeysCnt; mfKeyCounter++) { - num_to_bytes(mfKeys[mfKeyCounter], 6, (uint8_t*)(keyBlock + mfKeyCounter * 6)); - } + for (int mfKeyCounter = 0; mfKeyCounter < mfKeysCnt; mfKeyCounter++) { + num_to_bytes(mfKeys[mfKeyCounter], 6, (uint8_t *)(keyBlock + mfKeyCounter * 6)); + } - /* - Simple switch just to handle keytpes. - */ - switch (keyTypec) { - case 'a': case 'A': - keyType = !0; - break; - case 'b': case 'B': - keyType = !1; - break; - case '?': - keyType = 2; - break; - default: - Dbprintf("[!] Key type must be A , B or ?"); - keyType = 2; - } + /* + Pretty print of the keys to be checked. + */ + if (printKeys) { + Dbprintf("[+] Printing mf keys"); + for (uint8_t keycnt = 0; keycnt < mfKeysCnt; keycnt++) + Dbprintf("[-] chk mf key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, + (keyBlock + 6 * keycnt)[0], (keyBlock + 6 * keycnt)[1], (keyBlock + 6 * keycnt)[2], + (keyBlock + 6 * keycnt)[3], (keyBlock + 6 * keycnt)[4], (keyBlock + 6 * keycnt)[5], 6); + DbpString("--------------------------------------------------------"); + } - /* - Pretty print of the keys to be checked. - */ - if (printKeys) { - Dbprintf("[+] Printing mf keys"); - for (uint8_t keycnt = 0; keycnt < mfKeysCnt; keycnt++) - Dbprintf("[-] chk mf key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, - (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); - DbpString("--------------------------------------------------------"); - } + /* + Initialization of validKeys and foundKeys storages. + - validKey will store whether the sector has a valid A/B key. + - foundKey will store the found A/B key for each sector. + */ + bool validKey[2][40]; + uint8_t foundKey[2][40][6]; + for (uint16_t t = 0; t < 2; t++) { + for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { + validKey[t][sectorNo] = false; + for (uint16_t i = 0; i < 6; i++) { + foundKey[t][sectorNo][i] = 0xff; + } + } + } - /* - Initialization of validKeys and foundKeys storages. - - validKey will store whether the sector has a valid A/B key. - - foundKey will store the found A/B key for each sector. - */ - bool validKey[2][40]; - uint8_t foundKey[2][40][6]; - for (uint16_t t = 0; t < 2; t++) { - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - validKey[t][sectorNo] = false; - for (uint16_t i = 0; i < 6; i++) { - foundKey[t][sectorNo][i] = 0xff; - } - } - } + /* + Iterates through each sector checking if there is a correct key. + */ + bool err = 0; + bool allKeysFound = true; + uint32_t size = mfKeysCnt; - /* - Iterates through each sector checking if there is a correct key. - */ - int key = -1; - int block = 0; - bool err = 0; - bool allKeysFound = true; - uint32_t size = mfKeysCnt; - - for (int type = !keyType; type < 2 && !err; keyType == 2 ? (type++) : (type = 2)) { - block = blockNo; - for (int sec = 0; sec < sectorsCnt && !err; ++sec) { - Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B':'A', mfKeysCnt); - key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64); - if (key == -1) { - LED(LED_RED, 50); //red - Dbprintf("\t✕ Key not found for this sector!"); - allKeysFound = false; - // break; - } else if (key == -2) { - err = 1; // Can't select card. - break; - } else { - num_to_bytes(key64, 6, foundKey[type][sec]); - validKey[type][sec] = true; - keyFound = true; - Dbprintf("\t✓ Found valid key: [%02x%02x%02x%02x%02x%02x]\n", - (keyBlock + 6*key)[0], (keyBlock + 6*key)[1], (keyBlock + 6*key)[2], - (keyBlock + 6*key)[3], (keyBlock + 6*key)[4], (keyBlock + 6*key)[5] - ); - } - - block < 127 ? (block += 4) : (block += 16); - } - } + for (int type = !keyType; type < 2 && !err; keyType == 2 ? (type++) : (type = 2)) { + int block = blockNo; + for (int sec = 0; sec < sectorsCnt && !err; ++sec) { + Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt); + int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64); + if (key == -1) { + LED(LED_RED, 50); //red + Dbprintf("\t✕ Key not found for this sector!"); + allKeysFound = false; + // break; + } else if (key == -2) { + err = 1; // Can't select card. + break; + } else { + num_to_bytes(key64, 6, foundKey[type][sec]); + validKey[type][sec] = true; + keyFound = true; + Dbprintf("\t✓ Found valid key: [%02x%02x%02x%02x%02x%02x]\n", + (keyBlock + 6 * key)[0], (keyBlock + 6 * key)[1], (keyBlock + 6 * key)[2], + (keyBlock + 6 * key)[3], (keyBlock + 6 * key)[4], (keyBlock + 6 * key)[5] + ); + } - /* - TODO: This. + block < 127 ? (block += 4) : (block += 16); + } + } - - If at least one key was found, start a nested attack based on that key, and continue. - - - Get UID from tag and set accordingly in emulator memory and call mifare1ksim with right flags (iceman) - */ - if (!allKeysFound && keyFound) { - Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); - LED_C_ON(); //red - LED_A_ON(); //yellow - // Do nested attack, set allKeysFound = true; - // allKeysFound = true; - } else { - Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); - LED_C_ON(); //red - } + /* + TODO: + - Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman) + */ + if (!allKeysFound && keyFound) { + Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); + LED_C_ON(); //red + LED_A_ON(); //yellow + // no room to run nested attack on device (iceman) + // Do nested attack, set allKeysFound = true; + // allKeysFound = true; + } else { + Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); + LED_C_ON(); //red + } - /* - If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. - */ - if ((transferToEml) && (allKeysFound)) { - - emlClearMem(); - - uint8_t mblock[16]; - for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { - if (validKey[0][sectorNo] || validKey[1][sectorNo]) { - emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4) - for (uint16_t t = 0; t < 2; t++) { - if (validKey[t][sectorNo]) { - memcpy(mblock + t*10, foundKey[t][sectorNo], 6); - } - } - emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); - } - } - Dbprintf("\t✓ Found keys have been transferred to the emulator memory."); - if (ecfill) { - - Dbprintf("\tFilling in with key A."); - MifareECardLoad(sectorsCnt, 0, 0, &filled); - if (filled != 1) { - Dbprintf("\t✕ Failed filling with A."); - } - - Dbprintf("\tFilling in with key B."); - MifareECardLoad(sectorsCnt, 1, 0, &filled); - if (filled != 1) { - Dbprintf("\t✕ Failed filling with B."); - } - - if ((filled == 1) && simulation) { - Dbprintf("\t✓ Filled, simulation started."); - - // This will tell the fpga to emulate using previous keys and current target tag content. - Dbprintf("\t Press button to abort simulation at anytime."); - - LED_B_ON(); // green - // assuming arg0==0, use hardcoded uid 0xdeadbeaf - Mifare1ksim( 0, 0, 0, NULL); - LED_B_OFF(); + /* + If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. + */ + if ((transferToEml) && (allKeysFound)) { - /* - Needs further testing. - */ - if (fillFromEmulator) { - uint8_t retry = 5, cnt; - Dbprintf("\t Trying to dump into blank card."); - int flags = 0; - LED_A_ON(); //yellow - for (int blockNum = 0; blockNum < 16 * 4; blockNum += 1) { - cnt = 0; - emlGetMem(mblock, blockNum, 1); - // switch on field and send magic sequence - if (blockNum == 0) flags = 0x08 + 0x02; + emlClearMem(); - // just write - if (blockNum == 1) flags = 0; + uint8_t mblock[16]; + for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) { + if (validKey[0][sectorNo] || validKey[1][sectorNo]) { + emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4) + for (uint16_t t = 0; t < 2; t++) { + if (validKey[t][sectorNo]) { + memcpy(mblock + t * 10, foundKey[t][sectorNo], 6); + } + } + emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); + } + } + Dbprintf("\t✓ Found keys have been transferred to the emulator memory."); + if (ecfill) { + int filled; + Dbprintf("\tFilling in with key A."); + filled = MifareECardLoad(sectorsCnt, 0); + if (filled != PM3_SUCCESS) { + Dbprintf("\t✕ Failed filling with A."); + } - // Done. Magic Halt and switch off field. - if (blockNum == 16 * 4 - 1) flags = 0x04 + 0x10; + Dbprintf("\tFilling in with key B."); + filled = MifareECardLoad(sectorsCnt, 1); + if (filled != PM3_SUCCESS) { + Dbprintf("\t✕ Failed filling with B."); + } - while (!saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock) && cnt <= retry) { - cnt++; - Dbprintf("\t! Could not write block. Retrying."); - } - if (cnt == retry) { - Dbprintf("\t✕ Retries failed. Aborting."); - break; - } - } + if ((filled == PM3_SUCCESS) && simulation) { + Dbprintf("\t✓ Emulator memory filled, simulation started."); - if (!err) { - LED_B_ON(); - } else { - LED_C_ON(); - } + // This will tell the fpga to emulate using previous keys and current target tag content. + Dbprintf("\t Press button to abort simulation at anytime."); - } - } else if (filled != 1) { - Dbprintf("\t✕ Memory could not be filled due to errors."); - LED_C_ON(); - } - } - } -} \ No newline at end of file + LED_B_ON(); // green + // assuming arg0==0, use hardcoded uid 0xdeadbeaf + uint16_t simflags; + switch (p_card.uidlen) { + case 10: + simflags = FLAG_10B_UID_IN_DATA; + break; + case 7: + simflags = FLAG_7B_UID_IN_DATA; + break; + default: + simflags = FLAG_4B_UID_IN_DATA; + break; + } + Mifare1ksim(simflags | FLAG_MF_1K, 0, uid); + LED_B_OFF(); + + /* + Needs further testing. + */ + if (fillFromEmulator) { + uint8_t retry = 5; + Dbprintf("\t Trying to dump into blank card."); + int flags = 0; + LED_A_ON(); //yellow + for (int blockNum = 0; blockNum < 16 * 4; blockNum += 1) { + uint8_t cnt = 0; + emlGetMem(mblock, blockNum, 1); + // switch on field and send magic sequence + if (blockNum == 0) flags = 0x08 + 0x02; + + // just write + if (blockNum == 1) flags = 0; + + // Done. Magic Halt and switch off field. + if (blockNum == 16 * 4 - 1) flags = 0x04 + 0x10; + + while (!saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock) && cnt <= retry) { + cnt++; + Dbprintf("\t! Could not write block. Retrying."); + } + if (cnt == retry) { + Dbprintf("\t✕ Retries failed. Aborting."); + break; + } + } + + if (!err) { + LED_B_ON(); + } else { + LED_C_ON(); + } + + } + } else if (filled != PM3_SUCCESS) { + Dbprintf("\t✕ Emulator memory could not be filled due to errors."); + LED_C_ON(); + } + } + } +} diff --git a/armsrc/Standalone/hf_mattyrun.h b/armsrc/Standalone/hf_mattyrun.h index 508954998..5577e298a 100644 --- a/armsrc/Standalone/hf_mattyrun.h +++ b/armsrc/Standalone/hf_mattyrun.h @@ -12,11 +12,12 @@ #ifndef __HF_MATTYRUN_H #define __HF_MATTYRUN_H -//#include // for bool #include "standalone.h" // standalone definitions -#include "apps.h" // debugstatements, lfops? -#include "usb_cmd.h" // mifare1ksim flags +#include "apps.h" // debugstatements, lfops? +#include "pm3_cmd.h" // mifare1ksim flags +#include "mifaresim.h" // mifare1ksim +#include "mifareutil.h" #define OPTS 2 -#endif /* __HF_MATTYRUN_H */ \ No newline at end of file +#endif /* __HF_MATTYRUN_H */ diff --git a/armsrc/Standalone/hf_young.c b/armsrc/Standalone/hf_young.c index ef41bc64d..6b56935bd 100644 --- a/armsrc/Standalone/hf_young.c +++ b/armsrc/Standalone/hf_young.c @@ -11,251 +11,255 @@ #include "hf_young.h" typedef struct { - uint8_t uid[10]; - uint8_t uidlen; - uint8_t atqa[2]; - uint8_t sak; + uint8_t uid[10]; + uint8_t uidlen; + uint8_t atqa[2]; + uint8_t sak; } __attribute__((__packed__)) card_clone_t; +void ModInfo(void) { + DbpString(" HF Mifare sniff/simulation - (Craig Young)"); +} + void RunMod() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + StandAloneMode(); + Dbprintf(">> Craig Young Mifare sniff UID/clone uid 2 magic/sim a.k.a YoungRun Started <<"); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - int selected = 0, playing = 0, iGotoRecord = 0, iGotoClone = 0; - int cardRead[OPTS] = {0}; + int selected = 0, playing = 0, iGotoRecord = 0, iGotoClone = 0; + int cardRead[OPTS] = {0}; - card_clone_t uids[OPTS]; - iso14a_card_select_t card[OPTS]; - uint8_t params = (MAGIC_SINGLE | MAGIC_DATAIN); - - LED(selected + 1, 0); + card_clone_t uids[OPTS]; + iso14a_card_select_t card[OPTS]; + uint8_t params = (MAGIC_SINGLE | MAGIC_DATAIN); - for (;;) { - WDT_HIT(); - // exit from Standalone Mode, send a usbcommand. - if (usb_poll_validate_length()) return; + LED(selected + 1, 0); - SpinDelay(300); + for (;;) { + WDT_HIT(); + // exit from Standalone Mode, send a usbcommand. + if (data_available()) return; - if (iGotoRecord == 1 || cardRead[selected] == 0) { - iGotoRecord = 0; - LEDsoff(); - LED(selected + 1, 0); - LED(LED_RED2, 0); + SpinDelay(300); - // record - Dbprintf("Enabling iso14443a reader mode for [Bank: %d]...", selected); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + if (iGotoRecord == 1 || cardRead[selected] == 0) { + iGotoRecord = 0; + LEDsoff(); + LED(selected + 1, 0); + LED(LED_D, 0); - for (;;) { - // exit from Standalone Mode, send a usbcommand. - if (usb_poll_validate_length()) return; - - 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; // playing = 1; - } else { - Dbprintf("Button press detected but no stored tag to play. (Ignoring button)"); - SpinDelay(300); - } - } - - if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) { - continue; - } else { - Dbprintf("Read UID:"); - Dbhexdump(card[selected].uidlen, card[selected].uid, 0); - - if (memcmp(uids[(selected+1)%OPTS].uid, card[selected].uid, card[selected].uidlen ) == 0 ) { - Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping."); - } else { - uids[selected].sak = card[selected].sak; - uids[selected].uidlen = card[selected].uidlen; - memcpy(uids[selected].uid , card[selected].uid, uids[selected].uidlen); - memcpy(uids[selected].atqa, card[selected].atqa, 2); - - if (uids[selected].uidlen > 4) - Dbprintf("Bank[%d] received a 7-byte UID", selected); - else - Dbprintf("Bank[%d] received a 4-byte UID", selected); - break; - } - } - } - - Dbprintf("ATQA = %02X%02X", uids[selected].atqa[0], uids[selected].atqa[1]); - Dbprintf("SAK = %02X", uids[selected].sak); - LEDsoff(); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); + // record + Dbprintf("Enabling iso14443a reader mode for [Bank: %d]...", selected); + /* need this delay to prevent catching some weird data */ + SpinDelay(500); + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - LEDsoff(); - LED(selected + 1, 0); + for (;;) { + // exit from Standalone Mode, send a usbcommand. + if (data_available()) return; - // Next state is replay: - playing = 1; + 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; // playing = 1; + } else { + Dbprintf("Button press detected but no stored tag to play. (Ignoring button)"); + SpinDelay(300); + } + } - cardRead[selected] = 1; - } - - /* MF Classic UID clone */ - else if (iGotoClone==1) { - iGotoClone=0; - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 250); + if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) { + continue; + } else { + Dbprintf("Read UID:"); + Dbhexdump(card[selected].uidlen, card[selected].uid, 0); - // magiccards holds 4bytes uid. *usually* - uint32_t tmpuid = bytes_to_num(uids[selected].uid, 4); - - // record - Dbprintf("Preparing to Clone card [Bank: %d]; uid: %08x", selected, tmpuid); + if (memcmp(uids[(selected + 1) % OPTS].uid, card[selected].uid, card[selected].uidlen) == 0) { + Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping."); + } else { + uids[selected].sak = card[selected].sak; + uids[selected].uidlen = card[selected].uidlen; + memcpy(uids[selected].uid, card[selected].uid, uids[selected].uidlen); + memcpy(uids[selected].atqa, card[selected].atqa, 2); - // wait for button to be released - // Delay cloning until card is in place - while (BUTTON_PRESS()) - WDT_HIT(); + if (uids[selected].uidlen > 4) + Dbprintf("Bank[%d] received a 7-byte UID", selected); + else + Dbprintf("Bank[%d] received a 4-byte UID", selected); + break; + } + } + } - Dbprintf("Starting clone. [Bank: %d]", 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, {params & (0xFE | (uid == NULL ? 0:1)), blockNo, 0}}; - memcpy(c.d.asBytes, data, 16); - SendCommand(&c); + Dbprintf("ATQA = %02X%02X", uids[selected].atqa[0], uids[selected].atqa[1]); + Dbprintf("SAK = %02X", uids[selected].sak); + LEDsoff(); + LED(LED_B, 200); + LED(LED_A, 200); + LED(LED_B, 200); + LED(LED_A, 200); - Block read is similar: - UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, blockNo, 0}}; - We need to imitate that call with blockNo 0 to set a uid. + LEDsoff(); + LED(selected + 1, 0); - 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->d.asBytes); - break; - case CMD_MIFARE_CGETBLOCK: - MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes); - break; + // Next state is replay: + playing = 1; - 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, MAGIC_SINGLE) to write it - */ - uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0}; - // arg0 = Flags, arg1=blockNo - MifareCGetBlock(params, 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 = 1; - } else { - Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]); - memcpy(newBlock0, oldBlock0, 16); + cardRead[selected] = 1; + } - // Copy uid for bank (2nd is for longer UIDs not supported if classic) - memcpy(newBlock0, uids[selected].uid, 4); - newBlock0[4] = newBlock0[0] ^ newBlock0[1] ^ newBlock0[2] ^ newBlock0[3]; + /* MF Classic UID clone */ + else if (iGotoClone == 1) { + iGotoClone = 0; + LEDsoff(); + LED(selected + 1, 0); + LED(LED_A, 250); - // arg0 = workFlags, arg1 = blockNo, datain - MifareCSetBlock(params, 0, newBlock0); - MifareCGetBlock(params, 0, testBlock0); - - if (memcmp(testBlock0, newBlock0, 16)==0) { - DbpString("Cloned successfull!"); - cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it - playing = 0; - iGotoRecord = 1; - selected = (selected + 1) % OPTS; - } else { - Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected); - playing = 1; - } - } - LEDsoff(); - LED(selected + 1, 0); - } - - // Change where to record (or begin playing) - // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) - else if (playing==1) { - LEDsoff(); - LED(selected + 1, 0); + // magiccards holds 4bytes uid. *usually* + uint32_t tmpuid = bytes_to_num(uids[selected].uid, 4); - // Begin transmitting - LED(LED_GREEN, 0); - DbpString("Playing"); - for ( ; ; ) { - // exit from Standalone Mode, send a usbcommand. - if (usb_poll_validate_length()) return; - - int button_action = BUTTON_HELD(1000); - if ( button_action == 0) { // No button action, proceed with sim + // record + Dbprintf("Preparing to Clone card [Bank: %d]; uid: %08x", selected, tmpuid); - uint8_t flags = FLAG_4B_UID_IN_DATA; - uint8_t data[USB_CMD_DATA_SIZE] = {0}; // in case there is a read command received we shouldn't break + // wait for button to be released + // Delay cloning until card is in place + while (BUTTON_PRESS()) + WDT_HIT(); - memcpy(data, uids[selected].uid, uids[selected].uidlen); - - uint64_t tmpuid = bytes_to_num(uids[selected].uid, uids[selected].uidlen); - - if ( uids[selected].uidlen == 7 ) { - flags = FLAG_7B_UID_IN_DATA; - Dbprintf("Simulating ISO14443a tag with uid: %014" PRIx64 " [Bank: %d]", tmpuid, selected); - } else { - Dbprintf("Simulating ISO14443a tag with uid: %08" PRIx64 " [Bank: %d]", tmpuid, selected); - } - - if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) { - DbpString("Mifare Classic 1k"); - SimulateIso14443aTag(1, flags, data); - } else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) { - DbpString("Mifare Classic 4k (4b uid)"); - SimulateIso14443aTag(8, flags, data); - } else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { - DbpString("Mifare Classic 4k (7b uid)"); - SimulateIso14443aTag(8, flags, data); - } else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { - DbpString("Mifare Ultralight"); - SimulateIso14443aTag(2, flags, data); - } else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) { - DbpString("Mifare DESFire"); - SimulateIso14443aTag(3, flags, data); - } else { - Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); - SimulateIso14443aTag(1, flags, data); - } - - } else if (button_action == BUTTON_SINGLE_CLICK) { - selected = (selected + 1) % OPTS; - Dbprintf("Done playing. Switching to record mode on bank %d", selected); - iGotoRecord = 1; - break; - } else if (button_action == BUTTON_HOLD) { - Dbprintf("Playtime over. Begin cloning..."); - iGotoClone = 1; - break; - } - } + Dbprintf("Starting clone. [Bank: %d]", 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: + SendCommandOLD(CMD_MIFARE_CSETBLOCK, params & (0xFE | (uid == NULL ? 0:1)), blockNo, 0, data, 16); - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); - LEDsoff(); - LED(selected + 1, 0); - } - } -} \ No newline at end of file + Block read is similar: + SendCommandOLD(CMD_MIFARE_CGETBLOCK, params, blockNo, 0,...}; + 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->d.asBytes); + break; + case CMD_MIFARE_CGETBLOCK: + MifareCGetBlock(c->arg[0], c->arg[1], 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, MAGIC_SINGLE) to write it + */ + uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}; + // arg0 = Flags, arg1=blockNo + MifareCGetBlock(params, 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 = 1; + } else { + uint8_t testBlock0[16] = {0}; + Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]); + memcpy(newBlock0 + 5, oldBlock0 + 5, 11); + + // Copy uid for bank (2nd is for longer UIDs not supported if classic) + memcpy(newBlock0, uids[selected].uid, 4); + newBlock0[4] = newBlock0[0] ^ newBlock0[1] ^ newBlock0[2] ^ newBlock0[3]; + + // arg0 = workFlags, arg1 = blockNo, datain + MifareCSetBlock(params, 0, newBlock0); + MifareCGetBlock(params, 0, testBlock0); + + if (memcmp(testBlock0, newBlock0, 16) == 0) { + DbpString("Cloned successfull!"); + cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it + playing = 0; + iGotoRecord = 1; + selected = (selected + 1) % OPTS; + } else { + Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected); + playing = 1; + } + } + LEDsoff(); + LED(selected + 1, 0); + } + + // Change where to record (or begin playing) + // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) + else if (playing == 1) { + LEDsoff(); + LED(selected + 1, 0); + + // Begin transmitting + LED(LED_B, 0); + DbpString("Playing"); + for (; ;) { + // exit from Standalone Mode, send a usbcommand. + if (data_available()) return; + + int button_action = BUTTON_HELD(1000); + if (button_action == 0) { // No button action, proceed with sim + + uint8_t flags = FLAG_4B_UID_IN_DATA; + uint8_t data[PM3_CMD_DATA_SIZE] = {0}; // in case there is a read command received we shouldn't break + + memcpy(data, uids[selected].uid, uids[selected].uidlen); + + uint64_t tmpuid = bytes_to_num(uids[selected].uid, uids[selected].uidlen); + + if (uids[selected].uidlen == 7) { + flags = FLAG_7B_UID_IN_DATA; + Dbprintf("Simulating ISO14443a tag with uid: %014" PRIx64 " [Bank: %d]", tmpuid, selected); + } else { + Dbprintf("Simulating ISO14443a tag with uid: %08" PRIx64 " [Bank: %d]", tmpuid, selected); + } + + if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) { + DbpString("Mifare Classic 1k"); + SimulateIso14443aTag(1, flags, data); + } else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) { + DbpString("Mifare Classic 4k (4b uid)"); + SimulateIso14443aTag(8, flags, data); + } else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { + DbpString("Mifare Classic 4k (7b uid)"); + SimulateIso14443aTag(8, flags, data); + } else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { + DbpString("Mifare Ultralight"); + SimulateIso14443aTag(2, flags, data); + } else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) { + DbpString("Mifare DESFire"); + SimulateIso14443aTag(3, flags, data); + } else { + Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); + SimulateIso14443aTag(1, flags, data); + } + + } else if (button_action == BUTTON_SINGLE_CLICK) { + selected = (selected + 1) % OPTS; + Dbprintf("Done playing. Switching to record mode on bank %d", selected); + iGotoRecord = 1; + break; + } else if (button_action == BUTTON_HOLD) { + Dbprintf("Playtime over. Begin cloning..."); + iGotoClone = 1; + break; + } + } + + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); + LEDsoff(); + LED(selected + 1, 0); + } + } +} diff --git a/armsrc/Standalone/hf_young.h b/armsrc/Standalone/hf_young.h index 3ccd08b72..dcd8b13e7 100644 --- a/armsrc/Standalone/hf_young.h +++ b/armsrc/Standalone/hf_young.h @@ -16,7 +16,7 @@ #include "standalone.h" // standalone definitions #include "iso14443a.h" #include "protocols.h" - + #define OPTS 2 -#endif /* __HF_YOUNG_H */ \ No newline at end of file +#endif /* __HF_YOUNG_H */ diff --git a/armsrc/Standalone/lf_hidbrute.c b/armsrc/Standalone/lf_hidbrute.c index 7ec3aba28..06b0049ad 100644 --- a/armsrc/Standalone/lf_hidbrute.c +++ b/armsrc/Standalone/lf_hidbrute.c @@ -9,16 +9,16 @@ // the license. // // PROXMARK3 - HID CORPORATE 1000 BRUTEFORCER (STAND-ALONE MODE) -// -// This version of Proxmark3 firmware adds one extra stand-alone mode to proxmark3 firmware. +// +// This version of Proxmark3 firmware adds one extra stand-alone mode. // The new stand-alone mode allows to execute a bruteforce on HID Corporate 1000 readers, by // reading a specific badge and bruteforcing the Card Number (incrementing and decrementing it), // mainteining the same Facility Code of the original badge. // -// Based on an idea of Brad Antoniewicz of McAfee® Foundstone® Professional Services (ProxBrute), +// Based on an idea of Brad Antoniewicz of McAfee® Foundstone® Professional Services (ProxBrute), // the stand-alone mode has been rewritten in order to overcome some limitations of ProxBrute firmware, // that does not consider parity bits. -// +// // https://github.com/federicodotta/proxmark3 // //----------------------------------------------------------------------------------- @@ -26,297 +26,299 @@ //----------------------------------------------------------------------------------- #include "lf_hidbrute.h" +void ModInfo(void) { + DbpString(" LF HID corporate 1000 bruteforce - aka Corporatebrute (Federico dotta & Maurizio Agazzini)"); +} + // samy's sniff and repeat routine for LF void RunMod() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + StandAloneMode(); + Dbprintf(">> LF HID corporate bruteforce a.k.a CorporateBrute Started <<"); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - uint32_t high[OPTS], low[OPTS]; - int selected = 0; - int playing = 0; - int cardRead = 0; + uint32_t high[OPTS], low[OPTS]; + int selected = 0; + int playing = 0; + int cardRead = 0; - // Turn on selected LED - LED(selected + 1, 0); + // Turn on selected LED + LED(selected + 1, 0); - for (;;) { - WDT_HIT(); - - // exit from SamyRun, send a usbcommand. - if (usb_poll_validate_length()) break; + for (;;) { + WDT_HIT(); - // Was our button held down or pressed? - int button_pressed = BUTTON_HELD(1000); - SpinDelay(300); + // exit from SamyRun, send a usbcommand. + if (data_available()) break; - // Button was held for a second, begin recording - if (button_pressed > 0 && cardRead == 0) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_RED2, 0); + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); + SpinDelay(300); - // record - DbpString("[=] starting recording"); + // Button was held for a second, begin recording + if (button_pressed > 0 && cardRead == 0) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_D, 0); - // wait for button to be released - while(BUTTON_PRESS()) - WDT_HIT(); + // record + DbpString("[=] starting recording"); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); - Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]); + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - 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 = 1; - } - else if (button_pressed > 0 && cardRead == 1) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 0); + CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); + Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]); - // record - Dbprintf("[=] cloning %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 = 1; + } else if (button_pressed > 0 && cardRead == 1) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_A, 0); - // wait for button to be released - while(BUTTON_PRESS()) - WDT_HIT(); + // record + Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - CopyHIDtoT55x7(0, high[selected], low[selected], 0); - Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - LEDsoff(); - LED(selected + 1, 0); - // Finished recording + CopyHIDtoT55x7(0, high[selected], low[selected], 0); + Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); - // If we were previously playing, set playing off - // so next button push begins playing what we recorded - playing = 0; - cardRead = 0; - } + LEDsoff(); + LED(selected + 1, 0); + // Finished recording - // Change where to record (or begin playing) - else if (button_pressed) { - // Next option if we were previously playing - if (playing) - selected = (selected + 1) % OPTS; - - playing = !playing; + // If we were previously playing, set playing off + // so next button push begins playing what we recorded + playing = 0; + cardRead = 0; + } - LEDsoff(); - LED(selected + 1, 0); + // Change where to record (or begin playing) + else if (button_pressed) { + // Next option if we were previously playing + if (playing) + selected = (selected + 1) % OPTS; - // Begin transmitting - if (playing && selected != 2) { + playing = !playing; - LED(LED_GREEN, 0); - DbpString("[=] playing"); - - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); - - Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]); - CmdHIDsimTAG(high[selected], low[selected], 0); - DbpString("[=] done playing"); - - if (BUTTON_HELD(1000) > 0) - goto out; + LEDsoff(); + LED(selected + 1, 0); - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); + // Begin transmitting + if (playing && selected != 2) { - // when done, we're done playing, move to next option - selected = (selected + 1) % OPTS; - playing = !playing; - LEDsoff(); - LED(selected + 1, 0); - } - else if (playing && selected == 2) - { - // Now it work only with HID Corporate 1000 (35bit), but is easily extensible to others RFID. - // It is necessary only to calculate the correct parity. - - // Brute force code - // Check if the badge is an HID Corporate 1000 - if( (high[selected] & 0xFFFFFFF8) != 0x28 ) { - DbpString("[-] Card is not a HID Corporate 1000. Skipping bruteforce."); - continue; - } + LED(LED_B, 0); + DbpString("[=] playing"); - LED(LED_GREEN, 0); - DbpString("[=] entering bruteforce mode"); - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); - - // Calculate Facility Code and Card Number from high and low - uint32_t cardnum = (low[selected] >> 1) & 0xFFFFF; - uint32_t fc = ((high[selected] & 1 ) << 11 ) | (low[selected] >> 21); - uint32_t original_cardnum = cardnum; + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - Dbprintf("[=] Proxbrute - starting decrementing card number"); + Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]); + CmdHIDsimTAG(high[selected], low[selected], 0); + DbpString("[=] done playing"); - while (cardnum >= 0) { - - // Needed for exiting from proxbrute when button is pressed - if (BUTTON_PRESS()) { - if (BUTTON_HELD(1000) > 0) { - goto out; - } else { - while (BUTTON_PRESS()) { - WDT_HIT(); - } - break; - } - } + if (BUTTON_HELD(1000) > 0) + goto out; - // Decrement Card Number - cardnum--; + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); - // Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables - hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc); + // when done, we're done playing, move to next option + selected = (selected + 1) % OPTS; + playing = !playing; + LEDsoff(); + LED(selected + 1, 0); + } else if (playing && selected == 2) { + // Now it work only with HID Corporate 1000 (35bit), but is easily extensible to others RFID. + // It is necessary only to calculate the correct parity. - // Print actual code to brute - Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum); - - CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000); - } + // Brute force code + // Check if the badge is an HID Corporate 1000 + if ((high[selected] & 0xFFFFFFF8) != 0x28) { + DbpString("[-] Card is not a HID Corporate 1000. Skipping bruteforce."); + continue; + } - cardnum = original_cardnum; + LED(LED_B, 0); + DbpString("[=] entering bruteforce mode"); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - Dbprintf("[=] Proxbrute - starting incrementing card number"); + // Calculate Facility Code and Card Number from high and low + uint32_t cardnum = (low[selected] >> 1) & 0xFFFFF; + uint32_t fc = ((high[selected] & 1) << 11) | (low[selected] >> 21); + uint32_t original_cardnum = cardnum; - while (cardnum <= 0xFFFFF) { - - // Needed for exiting from proxbrute when button is pressed - if (BUTTON_PRESS()) { - if (BUTTON_HELD(1000) > 0) { - goto out; - } else { - while (BUTTON_PRESS()) { WDT_HIT(); } - break; - } - } + Dbprintf("[=] Proxbrute - starting decrementing card number"); - // Decrement Card Number - cardnum++; + while (cardnum > 0) { - // Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables - hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc); + // Needed for exiting from proxbrute when button is pressed + if (BUTTON_PRESS()) { + if (BUTTON_HELD(1000) > 0) { + goto out; + } else { + while (BUTTON_PRESS()) { + WDT_HIT(); + } + break; + } + } - // Print actual code to brute - Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum); + // Decrement Card Number + cardnum--; - CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000); - } + // Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables + hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc); - DbpString("[=] done bruteforcing"); - if (BUTTON_HELD(1000) > 0) - goto out; + // Print actual code to brute + Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum); - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); + CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000); + } - // when done, we're done playing, move to next option - selected = (selected + 1) % OPTS; - playing = !playing; - LEDsoff(); - LED(selected + 1, 0); - - } else { - while(BUTTON_PRESS()) - WDT_HIT(); - } - } - } - -out: - DbpString("[=] exiting"); - LEDsoff(); + cardnum = original_cardnum; + + Dbprintf("[=] Proxbrute - starting incrementing card number"); + + while (cardnum <= 0xFFFFF) { + + // Needed for exiting from proxbrute when button is pressed + if (BUTTON_PRESS()) { + if (BUTTON_HELD(1000) > 0) { + goto out; + } else { + while (BUTTON_PRESS()) { WDT_HIT(); } + break; + } + } + + // Decrement Card Number + cardnum++; + + // Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables + hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc); + + // Print actual code to brute + Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum); + + CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000); + } + + DbpString("[=] done bruteforcing"); + if (BUTTON_HELD(1000) > 0) + goto out; + + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); + + // when done, we're done playing, move to next option + selected = (selected + 1) % OPTS; + playing = !playing; + LEDsoff(); + LED(selected + 1, 0); + + } else { + while (BUTTON_PRESS()) + WDT_HIT(); + } + } + } + +out: + DbpString("[=] exiting"); + LEDsoff(); } // Function that calculate next value for the brutforce of HID corporate 1000 -void hid_corporate_1000_calculate_checksum_and_set( uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc) { +void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc) { - uint32_t new_high = 0; - uint32_t new_low = 0; + uint32_t new_high = 0; + uint32_t new_low = 0; - // Calculate new high and low base value from card number and facility code, without parity - new_low = (fc << 21) | (cardnum << 1); - new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000 + // Calculate new high and low base value from card number and facility code, without parity + new_low = (fc << 21) | (cardnum << 1); + new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000 - int n_ones; - uint32_t i; - - // Calculating and setting parity bit 34 - // Select only bit used for parity bit 34 in low number (10110110110110110110110110110110) - uint32_t parity_bit_34_low = new_low & 0xB6DB6DB6; - n_ones = 0; - // Calculate number of ones in low number - for ( i = 1; i != 0; i <<= 1) { - if( parity_bit_34_low & i ) - n_ones++; - } - // Calculate number of ones in high number - if (new_high & 1) - n_ones++; - - // Set parity bit (Even parity) - if (n_ones % 2) - new_high = new_high | 0x2; + int n_ones; + uint32_t i; - // Calculating and setting parity bit 1 - // Select only bit used for parity bit 1 in low number (01101101101101101101101101101100) - uint32_t parity_bit_1_low = new_low & 0x6DB6DB6C; - n_ones = 0; + // Calculating and setting parity bit 34 + // Select only bit used for parity bit 34 in low number (10110110110110110110110110110110) + uint32_t parity_bit_34_low = new_low & 0xB6DB6DB6; + n_ones = 0; + // Calculate number of ones in low number + for (i = 1; i != 0; i <<= 1) { + if (parity_bit_34_low & i) + n_ones++; + } + // Calculate number of ones in high number + if (new_high & 1) + n_ones++; - // Calculate number of ones in low number - for ( i=1; i != 0; i <<= 1) { - if( parity_bit_1_low & i ) - n_ones++; - } - // Calculate number of ones in high number - if ( new_high & 0x1) - n_ones++; - - if ( new_high & 0x2) - n_ones++; - - // Set parity bit (Odd parity) - if (!(n_ones % 2)) - new_low = new_low | 0x1; - - // Calculating and setting parity bit 35 - n_ones = 0; - // Calculate number of ones in low number (all bit of low, bitmask unnecessary) - for (i = 1; i != 0; i <<= 1) { - if ( new_low & i ) - n_ones++; - } - // Calculate number of ones in high number - if ( new_high & 0x1) - n_ones++; - - if ( new_high & 0x2) - n_ones++; + // Set parity bit (Even parity) + if (n_ones % 2) + new_high = new_high | 0x2; - // Set parity bit (Odd parity) - if (!(n_ones % 2)) - new_high = new_high | 0x4; + // Calculating and setting parity bit 1 + // Select only bit used for parity bit 1 in low number (01101101101101101101101101101100) + uint32_t parity_bit_1_low = new_low & 0x6DB6DB6C; + n_ones = 0; - // Setting new calculated values - *low = new_low; - *high = new_high; + // Calculate number of ones in low number + for (i = 1; i != 0; i <<= 1) { + if (parity_bit_1_low & i) + n_ones++; + } + // Calculate number of ones in high number + if (new_high & 0x1) + n_ones++; + + if (new_high & 0x2) + n_ones++; + + // Set parity bit (Odd parity) + if (!(n_ones % 2)) + new_low = new_low | 0x1; + + // Calculating and setting parity bit 35 + n_ones = 0; + // Calculate number of ones in low number (all bit of low, bitmask unnecessary) + for (i = 1; i != 0; i <<= 1) { + if (new_low & i) + n_ones++; + } + // Calculate number of ones in high number + if (new_high & 0x1) + n_ones++; + + if (new_high & 0x2) + n_ones++; + + // Set parity bit (Odd parity) + if (!(n_ones % 2)) + new_high = new_high | 0x4; + + // Setting new calculated values + *low = new_low; + *high = new_high; } // prepare a waveform pattern in the buffer based on the ID given then diff --git a/armsrc/Standalone/lf_hidbrute.h b/armsrc/Standalone/lf_hidbrute.h index 4cd2d5631..49b0af6c6 100644 --- a/armsrc/Standalone/lf_hidbrute.h +++ b/armsrc/Standalone/lf_hidbrute.h @@ -19,6 +19,6 @@ #define OPTS 3 -void hid_corporate_1000_calculate_checksum_and_set( uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc); +void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc); -#endif /* __LF_HIDBRUTE_H */ \ No newline at end of file +#endif /* __LF_HIDBRUTE_H */ diff --git a/armsrc/Standalone/lf_icerun.c b/armsrc/Standalone/lf_icerun.c new file mode 100644 index 000000000..e62c79329 --- /dev/null +++ b/armsrc/Standalone/lf_icerun.c @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// Christian Herrmann, 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. +//----------------------------------------------------------------------------- +// main code for skeleton aka IceRun by Iceman +//----------------------------------------------------------------------------- +#include "lf_icerun.h" + +void ModInfo(void) { + DbpString(" LF skeleton mode - aka IceRun (iceman)"); +} + +// samy's sniff and repeat routine for LF +void RunMod() { + StandAloneMode(); + Dbprintf("[=] LF skeleton code a.k.a IceRun started"); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + // the main loop for your standalone mode + for (;;) { + WDT_HIT(); + + // exit from IceRun, send a usbcommand. + if (data_available()) break; + + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); + + Dbprintf("button %d", button_pressed); + + if (button_pressed) + break; + } + + DbpString("[=] exiting"); + LEDsoff(); +} diff --git a/common/random.h b/armsrc/Standalone/lf_icerun.h similarity index 57% rename from common/random.h rename to armsrc/Standalone/lf_icerun.h index 800ad8103..50427320a 100644 --- a/common/random.h +++ b/armsrc/Standalone/lf_icerun.h @@ -1,21 +1,17 @@ //----------------------------------------------------------------------------- -// Micolous Jan 2017 -// Iceman Jan 2017 +// Iceman, Christian Herrmann, 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. //----------------------------------------------------------------------------- -// pseudo rng generator. To be used when PM3 simulates Mifare tag. -// i.e. 'hf mf sim' -// 'hf 14a sim' +// StandAlone Mod //----------------------------------------------------------------------------- -#ifndef __RANDOM_H -#define __RANDOM_H +#ifndef __LF_ICERUN_H +#define __LF_ICERUN_H -#include "common.h" -#include "ticks.h" -void fast_prand(); -void fast_prandEx(uint32_t seed); -uint32_t prand(); -#endif \ No newline at end of file +#include "standalone.h" // standalone definitions +#include "apps.h" // debugstatements, lfops? + +#endif /* __LF_ICERUN_H */ diff --git a/armsrc/Standalone/lf_proxbrute.c b/armsrc/Standalone/lf_proxbrute.c index e0c998d31..d10a1fbfe 100644 --- a/armsrc/Standalone/lf_proxbrute.c +++ b/armsrc/Standalone/lf_proxbrute.c @@ -7,162 +7,165 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// main code for LF aka Proxbrute by Brad antoniewicz +// main code for LF aka Proxbrute by Brad antoniewicz //----------------------------------------------------------------------------- #include "lf_proxbrute.h" +void ModInfo(void) { + DbpString(" LF HID ProxII bruteforce - aka Proxbrute (Brad Antoniewicz)"); +} + // samy's sniff and repeat routine for LF void RunMod() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + StandAloneMode(); + Dbprintf(">> LF HID proxII bruteforce a.k.a ProxBrute Started (Brad Antoniewicz) <<"); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - uint32_t high[OPTS], low[OPTS]; - int selected = 0; - int playing = 0; - int cardRead = 0; + uint32_t high[OPTS], low[OPTS]; + int selected = 0; + int playing = 0; + int cardRead = 0; - // Turn on selected LED - LED(selected + 1, 0); + // Turn on selected LED + LED(selected + 1, 0); - for (;;) { - WDT_HIT(); - - // exit from SamyRun, send a usbcommand. - if (usb_poll_validate_length()) break; + for (;;) { + WDT_HIT(); - // Was our button held down or pressed? - int button_pressed = BUTTON_HELD(1000); - SpinDelay(300); + // exit from SamyRun, send a usbcommand. + if (data_available()) break; - // Button was held for a second, begin recording - if (button_pressed > 0 && cardRead == 0) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_RED2, 0); + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); + SpinDelay(300); - // record - DbpString("[=] starting recording"); + // Button was held for a second, begin recording + if (button_pressed > 0 && cardRead == 0) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_D, 0); - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); + // record + DbpString("[=] starting recording"); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); - Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]); + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - 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 = 1; - } - else if (button_pressed > 0 && cardRead == 1) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 0); + CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); + Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]); - // record - Dbprintf("[=] cloning %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 = 1; + } else if (button_pressed > 0 && cardRead == 1) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_A, 0); - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); + // record + Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - CopyHIDtoT55x7(0, high[selected], low[selected], 0); - Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - LEDsoff(); - LED(selected + 1, 0); - // Finished recording + CopyHIDtoT55x7(0, high[selected], low[selected], 0); + Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); - // If we were previously playing, set playing off - // so next button push begins playing what we recorded - playing = 0; - cardRead = 0; - } + LEDsoff(); + LED(selected + 1, 0); + // Finished recording - // Change where to record (or begin playing) - else if (button_pressed) { - // Next option if we were previously playing - if (playing) - selected = (selected + 1) % OPTS; - playing = !playing; + // If we were previously playing, set playing off + // so next button push begins playing what we recorded + playing = 0; + cardRead = 0; + } - LEDsoff(); - LED(selected + 1, 0); + // Change where to record (or begin playing) + else if (button_pressed) { + // Next option if we were previously playing + if (playing) + selected = (selected + 1) % OPTS; + playing = !playing; - // Begin transmitting - if (playing) { - LED(LED_GREEN, 0); - DbpString("[=] playing"); - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); - - /* START PROXBRUTE */ + LEDsoff(); + LED(selected + 1, 0); - /* - ProxBrute - brad a. - foundstone + // Begin transmitting + if (playing) { + LED(LED_B, 0); + DbpString("[=] playing"); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - Following code is a trivial brute forcer once you read a valid tag - the idea is you get a valid tag, then just try and brute force to - another priv level. The problem is that it has no idea if the code - worked or not, so its a crap shoot. One option is to time how long - it takes to get a valid ID then start from scratch every time. - */ - if ( selected == 1 ) { - DbpString("[=] entering ProxBrute Mode"); - Dbprintf("[=] current Tag: Selected = %x Facility = %08x ID = %08x", selected, high[selected], low[selected]); - LED(LED_ORANGE, 0); - LED(LED_RED, 0); - for (uint16_t i = low[selected]-1; i > 0; i--) { - if (BUTTON_PRESS()) { - DbpString("[-] told to stop"); - break; - } + /* START PROXBRUTE */ - Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i); - CmdHIDsimTAGEx(high[selected], i, 0, 20000); - SpinDelay(500); - } + /* + ProxBrute - brad a. - foundstone - } else { - DbpString("[=] RED is lit, not entering ProxBrute Mode"); - Dbprintf("[=] %x %x %x", selected, high[selected], low[selected]); - CmdHIDsimTAGEx(high[selected], low[selected], 0, 20000); - DbpString("[=] done playing"); - } + Following code is a trivial brute forcer once you read a valid tag + the idea is you get a valid tag, then just try and brute force to + another priv level. The problem is that it has no idea if the code + worked or not, so its a crap shoot. One option is to time how long + it takes to get a valid ID then start from scratch every time. + */ + if (selected == 1) { + DbpString("[=] entering ProxBrute Mode"); + Dbprintf("[=] current Tag: Selected = %x Facility = %08x ID = %08x", selected, high[selected], low[selected]); + LED(LED_A, 0); + LED(LED_C, 0); + for (uint16_t i = low[selected] - 1; i > 0; i--) { + if (BUTTON_PRESS()) { + DbpString("[-] told to stop"); + break; + } - /* END PROXBRUTE */ + Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i); + CmdHIDsimTAGEx(high[selected], i, 0, 20000); + SpinDelay(500); + } - - if (BUTTON_HELD(1000) > 0) - goto out; + } else { + DbpString("[=] RED is lit, not entering ProxBrute Mode"); + Dbprintf("[=] %x %x %x", selected, high[selected], low[selected]); + CmdHIDsimTAGEx(high[selected], low[selected], 0, 20000); + DbpString("[=] done playing"); + } - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); + /* END PROXBRUTE */ - // when done, we're done playing, move to next option - selected = (selected + 1) % OPTS; - playing = !playing; - LEDsoff(); - LED(selected + 1, 0); - } - else { - while (BUTTON_PRESS()) - WDT_HIT(); - } - } - } -out: - DbpString("[=] exiting"); - LEDsoff(); -} \ No newline at end of file + + if (BUTTON_HELD(1000) > 0) + goto out; + + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); + + // when done, we're done playing, move to next option + selected = (selected + 1) % OPTS; + playing = !playing; + LEDsoff(); + LED(selected + 1, 0); + } else { + while (BUTTON_PRESS()) + WDT_HIT(); + } + } + } +out: + DbpString("[=] exiting"); + LEDsoff(); +} diff --git a/armsrc/Standalone/lf_proxbrute.h b/armsrc/Standalone/lf_proxbrute.h index 3911fee35..3a9e1ce29 100644 --- a/armsrc/Standalone/lf_proxbrute.h +++ b/armsrc/Standalone/lf_proxbrute.h @@ -18,4 +18,4 @@ #define OPTS 2 -#endif /* __LF_PROXBRUTE_H */ \ No newline at end of file +#endif /* __LF_PROXBRUTE_H */ diff --git a/armsrc/Standalone/lf_samyrun.c b/armsrc/Standalone/lf_samyrun.c index 88b6e9b15..03c2ddd12 100644 --- a/armsrc/Standalone/lf_samyrun.c +++ b/armsrc/Standalone/lf_samyrun.c @@ -6,137 +6,140 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// main code for LF aka SamyRun by Samy Kamkar +// main code for LF aka SamyRun by Samy Kamkar //----------------------------------------------------------------------------- #include "lf_samyrun.h" +void ModInfo(void) { + DbpString(" LF HID26 standalone - aka SamyRun (Samy Kamkar)"); +} + // samy's sniff and repeat routine for LF void RunMod() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + StandAloneMode(); + Dbprintf(">> LF HID Read/Clone/Sim a.k.a SamyRun Started <<"); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - uint32_t high[OPTS], low[OPTS]; - int selected = 0; - int playing = 0; - int cardRead = 0; - bool gotCard; - // Turn on selected LED - LED(selected + 1, 0); + uint32_t high[OPTS], low[OPTS]; + int selected = 0; + int playing = 0; + int cardRead = 0; + bool gotCard; + // Turn on selected LED + LED(selected + 1, 0); - for (;;) { - WDT_HIT(); - - // exit from SamyRun, send a usbcommand. - if (usb_poll_validate_length()) break; + for (;;) { + WDT_HIT(); - // Was our button held down or pressed? - int button_pressed = BUTTON_HELD(1000); - - Dbprintf("button %d", button_pressed); - SpinDelay(300); + // exit from SamyRun, send a usbcommand. + if (data_available()) break; - // Button was held for a second, begin recording - if (button_pressed > 0 && cardRead == 0) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_RED2, 0); + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); - // record - DbpString("[=] starting recording"); + Dbprintf("button %d", button_pressed); + SpinDelay(300); - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); + // Button was held for a second, begin recording + if (button_pressed > 0 && cardRead == 0) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_D, 0); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // record + DbpString("[=] starting recording"); - CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); - Dbprintf("[=] recorded bank %x | %x %08x", selected, high[selected], low[selected]); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - 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 = 1; + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - gotCard = true; - } - else if (button_pressed > 0 && cardRead == 1) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 0); + CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); + Dbprintf("[=] recorded bank %x | %x %08x", selected, high[selected], low[selected]); - // record - Dbprintf("[=] cloning %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 = 1; - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); + gotCard = true; + } else if (button_pressed > 0 && cardRead == 1) { + LEDsoff(); + LED(selected + 1, 0); + LED(LED_A, 0); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); + // record + Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]); - CopyHIDtoT55x7(0, high[selected], low[selected], 0); - Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); - LEDsoff(); - LED(selected + 1, 0); - // Finished recording + /* need this delay to prevent catching some weird data */ + SpinDelay(500); - // If we were previously playing, set playing off - // so next button push begins playing what we recorded - playing = 0; - cardRead = 0; - } + CopyHIDtoT55x7(0, high[selected], low[selected], 0); + Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]); - // Change where to record (or begin playing) - else if (button_pressed && gotCard) { - // Next option if we were previously playing - if (playing) - selected = (selected + 1) % OPTS; - - playing = !playing; + LEDsoff(); + LED(selected + 1, 0); + // Finished recording - LEDsoff(); - LED(selected + 1, 0); + // If we were previously playing, set playing off + // so next button push begins playing what we recorded + playing = 0; + cardRead = 0; + } - // Begin transmitting - if (playing) { - - LED(LED_GREEN, 0); - DbpString("[=] playing"); - - // wait for button to be released - while (BUTTON_PRESS()) - WDT_HIT(); - - Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]); - CmdHIDsimTAG(high[selected], low[selected], false); - DbpString("[=] done playing"); - - if (BUTTON_HELD(1000) > 0) - goto out; + // Change where to record (or begin playing) + else if (button_pressed && gotCard) { + // Next option if we were previously playing + if (playing) + selected = (selected + 1) % OPTS; - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); + playing = !playing; - // when done, we're done playing, move to next option - selected = (selected + 1) % OPTS; - playing = !playing; - LEDsoff(); - LED(selected + 1, 0); - } - else { - while (BUTTON_PRESS()) - WDT_HIT(); - } - } - } + LEDsoff(); + LED(selected + 1, 0); -out: - DbpString("[=] exiting"); - LEDsoff(); -} \ No newline at end of file + // Begin transmitting + if (playing) { + + LED(LED_B, 0); + DbpString("[=] playing"); + + // wait for button to be released + while (BUTTON_PRESS()) + WDT_HIT(); + + Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]); + CmdHIDsimTAG(high[selected], low[selected], false); + DbpString("[=] done playing"); + + if (BUTTON_HELD(1000) > 0) + goto out; + + /* We pressed a button so ignore it here with a delay */ + SpinDelay(300); + + // when done, we're done playing, move to next option + selected = (selected + 1) % OPTS; + playing = !playing; + LEDsoff(); + LED(selected + 1, 0); + } else { + while (BUTTON_PRESS()) + WDT_HIT(); + } + } + } + +out: + DbpString("[=] exiting"); + LEDsoff(); +} diff --git a/armsrc/Standalone/lf_samyrun.h b/armsrc/Standalone/lf_samyrun.h index cf21e1261..52c0bb942 100644 --- a/armsrc/Standalone/lf_samyrun.h +++ b/armsrc/Standalone/lf_samyrun.h @@ -19,4 +19,4 @@ #define OPTS 2 -#endif /* __LF_SAMYRUN_H */ \ No newline at end of file +#endif /* __LF_SAMYRUN_H */ diff --git a/armsrc/Standalone/placeholder.c b/armsrc/Standalone/placeholder.c new file mode 100644 index 000000000..e179bc876 --- /dev/null +++ b/armsrc/Standalone/placeholder.c @@ -0,0 +1,9 @@ +#include "standalone.h" // standalone definitions +#include "apps.h" // debug statements + +void ModInfo(void) { + DbpString(" No standalone mode present"); +} + +void RunMod() { +} diff --git a/armsrc/Standalone/readme.md b/armsrc/Standalone/readme.md index 618fcdc13..491490b1b 100644 --- a/armsrc/Standalone/readme.md +++ b/armsrc/Standalone/readme.md @@ -1,102 +1,138 @@ -# StandAlone Modes +# Standalone Modes -This contains functionality for different StandAlone modes. The fullimage will be built given the correct compiler flags used. Build targets for these files are contained in `armsrc/Makefile`. +This contains functionality for different StandAlone modes. The fullimage will be built given the correct compiler flags used. Build targets for these files are contained in `armsrc/Makefile` and `common/Makefile.hal` If you want to implement a new standalone mode, you need to implement the methods provided in `standalone.h`. - -## Implementing a standalone mode - -Each standalone mod needs to have its own compiler flag to be added in `armsrc\makefile` and inside the function `AppMain` inside AppMain.c. Inside Appmain a call to RunMod is needed. It looks strange because of what kinds of dependencies your mode will have. - -The RunMod function is your "main" function when running. You need to check for Usb commands, in order to let the pm3 client break the standalone mode. See this basic skeleton of main function RunMod(). -```` -void RunMod() { - // led show - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // main loop - for (;;) { - WDT_HIT(); - - // exit from standalone mode, just send a usbcommand - if (usb_poll_validate_length()) break; - - // do your standalone stuff.. - } -```` +Have a look at the skeleton standalone mode called IceRun, in the files `lf_icerun.c lf_icerun.h`. As it is now, you can only have one standalone mode installed at the time. -## Name -Use HF/LF to denote which frequence your mod is targeting. -Use you own github name/similar for perpetual honour to denote your mod +## Implementing a standalone mode -Samples of directive flag used in the `armsrc\makefile`: +We suggest you keep your standalone code inside the `armsrc/Standalone` folder. And that you name your files according to your standalone mode name. + +The `standalone.h` states that you must have two functions implemented. + +The ModInfo function, which is your identification of your standalone mode. This string will show when running the command `hw status` on the client. + +The RunMod function, which is your "main" function when running. You need to check for Usb commands, in order to let the pm3 client break the standalone mode. See this basic skeleton of main function RunMod() and Modinfo() below. + +```` +void ModInfo(void) { + DbpString(" LF good description of your mode - aka FooRun (your name)"); +} + +void RunMod(void) { + // led show + StandAloneMode(); + + // Do you target LF or HF? + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + // main loop + for (;;) { + WDT_HIT(); + + // exit from standalone mode, just send a usbcommand + if (data_available()) break; + + // do your standalone stuff.. + } +```` + +Each standalone mode needs to have its own compiler flag to be added in `armsrc/Makefile`. + +## Naming your standalone mode + +We suggest that you follow these guidelines: +- Use HF/LF to denote which frequency your mode is targeting. +- Use you own github name/similar for perpetual honour to denote your mode. + +sample: + `LF_FOO` + +Which indicates your mode targets LF and is called FOO. + +This leads to your next step, your DEFINE name needed in Makefile. + +`WITH_STANDALONE_LF_FOO` + + +## Update COMMON/MAKEFILE.HAL + +Add your mode to the `common/Makefile.hal` help and modes list: ``` -### -DWITH_LF_ICERUN -### -DWITH_LF_SAMYRUN -### -DWITH_LF_PROXBRUTE -### -DWITH_LF_HIDBRUTE -### -DWITH_HF_COLIN -### -DWITH_HF_YOUNG -### -DWITH_HF_MATTYRUN ++==========================================================+ +| STANDALONE | DESCRIPTION | ++==========================================================+ +... ++----------------------------------------------------------+ +| LF_FOO | My foobar mode will make you coffee | ++----------------------------------------------------------+ + +STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_FOO +STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG ``` -Add your source code file like the following sample in the `armsrc\makefile` + +## Update ARMSRC/MAKEFILE +Add your source code files like the following sample in the `armsrc/Makefile` ``` -# WITH_HF_COLIN -ifneq (,$(findstring WITH_HF_COLIN,$(APP_CFLAGS))) - SRC_STANDALONE = hf_colin.c vtsend.c -else - SRC_STANDALONE = +# WITH_STANDALONE_LF_ICERUN +ifneq (,$(findstring WITH_STANDALONE_LF_ICERUN,$(APP_CFLAGS))) + SRC_STANDALONE = lf_icerun.c +endif + +# WITH_STANDALONE_LF_FOO +ifneq (,$(findstring WITH_STANDALONE_LF_FOO,$(APP_CFLAGS))) + SRC_STANDALONE = lf_foo.c endif ``` -## Adding identification of your mode -Do please add a identification string in the function `printStandAloneModes` inside `armsrc\appmain.c` -This will enable an easy way to detect on client side which standalone mods has been installed on the device. +## Adding identification string of your mode +Do please add a identification string in a function called `ModInfo` inside your source code file. +This will enable an easy way to detect on client side which standalone mode has been installed on the device. + +```` +void ModInfo(void) { + DbpString(" LF good description of your mode - aka FooRun (your name)"); +} +```` + +## Compiling your standalone mode +Once all this is done, you and others can now easily compile different standalone modes by just selecting one of the standalone modes (list in `common/Makefile.hal` or ) , e.g.: + +- rename Makefile.platform.sample -> Makefile.platform +- edit the "STANDALONE" row inside Makefile.platform. You need to uncomment it and add your standalone mode name + +Makefile.platform.sample +``` +# If you want to use it, copy this file as Makefile.platform and adjust it to your needs +PLATFORM=PM3RDV4 +#PLATFORM_EXTRAS=BTADDON +#STANDALONE=LF_SAMYRUN +``` + becomes + + Makefile.platform + ``` +# If you want to use it, copy this file as Makefile.platform and adjust it to your needs +PLATFORM=PM3RDV4 +#PLATFORM_EXTRAS=BTADDON +STANDALONE=LF_FOO ``` -#if defined(WITH_HF_COLIN) - DbpString(" HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN (Colin Brigato)"); -#endif -```` -Once all this is done, you and others can now easily compile different standalone modes by just swapping the -D directive in `armsrc\makefile` +Remember only one can be selected at a time for now. -```` -#remove one of the following defines and comment out the relevant line -#in the next section to remove that particular feature from compilation. -# NO space,TABs after the "\" sign. -APP_CFLAGS = -DWITH_CRC \ - -DON_DEVICE \ - -DWITH_LF \ - -DWITH_HITAG \ - -DWITH_ISO15693 \ - -DWITH_LEGICRF \ - -DWITH_ISO14443b \ - -DWITH_ISO14443a \ - -DWITH_ICLASS \ - -DWITH_FELICA \ - -DWITH_FLASH \ - -DWITH_SMARTCARD \ - -DWITH_HFSNOOP \ - -DWITH_HF_COLIN\ - -DWITH_FPC \ - -fno-strict-aliasing -ffunction-sections -fdata-sections +The final steps is to +- force recompilation of all code. ```make clean``` +- compile ```make -j8``` +- flash your device +- connect to your device +- press button long time to trigger ledshow and enter your new standalone mode +- if connected with usb / fpc , you can also see debug statements from your device in standalone mode. Useful for debugging :) -### IMPORTANT - move the commented variable below this line -# -DWITH_LCD \ -# -DWITH_EMV \ -# -DWITH_FPC \ -# -# Standalone Mods -#------------------------------------------------------- -# -DWITH_LF_ICERUN -# -DWITH_LF_SAMYRUN -# -DWITH_LF_PROXBRUTE -# -DWITH_LF_HIDBRUTE -# -DWITH_HF_YOUNG -# -DWITH_HF_MATTYRUN -# -DWITH_HF_COLIN -```` +When compiling you will see a header showing what configurations your project compiled with. +Make sure it says your standalone mode name. + +Happy hacking! diff --git a/armsrc/Standalone/standalone.h b/armsrc/Standalone/standalone.h index 53d5ff13d..217c7b4cf 100644 --- a/armsrc/Standalone/standalone.h +++ b/armsrc/Standalone/standalone.h @@ -14,6 +14,7 @@ #include // for bool #include // PRIu64 -extern void RunMod(); +void RunMod(); +void ModInfo(); -#endif /* __STANDALONE_H */ \ No newline at end of file +#endif /* __STANDALONE_H */ diff --git a/armsrc/aes.c b/armsrc/aes.c index dc89a1cf0..f8a36f28c 100644 --- a/armsrc/aes.c +++ b/armsrc/aes.c @@ -672,20 +672,19 @@ static const unsigned int rcon[] = { ((unsigned int)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \ - (ct)[1] = (unsigned char)((st) >> 16); \ - (ct)[2] = (unsigned char)((st) >> 8); \ - (ct)[3] = (unsigned char)(st); } + (ct)[1] = (unsigned char)((st) >> 16); \ + (ct)[2] = (unsigned char)((st) >> 8); \ + (ct)[3] = (unsigned char)(st); } /* * Expand the cipher key into the encryption key schedule and return the * number of rounds for the given cipher key size. */ -int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) -{ +int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) { int i = 0; unsigned int temp; - rk[0] = GETU32(cipherKey ); + rk[0] = GETU32(cipherKey); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); @@ -693,11 +692,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy for (;;) { temp = rk[3]; rk[4] = rk[0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; @@ -713,11 +712,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; @@ -735,11 +734,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ - (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ - (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ - (Te4[(temp ) & 0xff] & 0x0000ff00) ^ - (Te4[(temp >> 24) ] & 0x000000ff) ^ - rcon[i]; + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; @@ -748,10 +747,10 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy } temp = rk[11]; rk[12] = rk[ 4] ^ - (Te4[(temp >> 24) ] & 0xff000000) ^ - (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ - (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(temp ) & 0xff] & 0x000000ff); + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; @@ -766,8 +765,7 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy * Expand the cipher key into encryption and decryption key schedule and * return the number of rounds for the given cipher key size. */ -int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) -{ +int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) { int Nr, i; // expand the cipher key @@ -779,10 +777,10 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci rrk[2] = rk[2]; rrk[3] = rk[3]; - /* - * apply the inverse MixColumn transform to all round keys but the first - * and the last - */ + /* + * apply the inverse MixColumn transform to all round keys but the first + * and the last + */ for (i = 1; i < Nr; i++) { rrk -= 4; rk += 4; @@ -790,22 +788,22 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + Td3[Te4[(rk[0]) & 0xff] & 0xff]; rrk[1] = Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + Td3[Te4[(rk[1]) & 0xff] & 0xff]; rrk[2] = Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + Td3[Te4[(rk[2]) & 0xff] & 0xff]; rrk[3] = Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ - Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + Td3[Te4[(rk[3]) & 0xff] & 0xff]; } // invert the order of the last round keys rrk -= 4; @@ -821,8 +819,7 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci /* * Encrypt the plain text into cipher */ -void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) -{ +void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) { unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv; const unsigned int *rk; int r; @@ -833,7 +830,7 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) * map byte array block to cipher state * and add initial round key: */ - s0 = GETU32(pt ) ^ rk[0]; + s0 = GETU32(pt) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; @@ -852,25 +849,25 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ - Te3[(s3 ) & 0xff] ^ + Te3[(s3) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ - Te3[(s0 ) & 0xff] ^ + Te3[(s0) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ - Te3[(s1 ) & 0xff] ^ + Te3[(s1) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ - Te3[(s2 ) & 0xff] ^ + Te3[(s2) & 0xff] ^ rk[7]; rk += 8; @@ -882,25 +879,25 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ - Te3[(t3 ) & 0xff] ^ + Te3[(t3) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ - Te3[(t0 ) & 0xff] ^ + Te3[(t0) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ - Te3[(t1 ) & 0xff] ^ + Te3[(t1) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ - Te3[(t2 ) & 0xff] ^ + Te3[(t2) & 0xff] ^ rk[3]; } /* @@ -911,28 +908,28 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) (Te4[(t0 >> 24) ] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + (Te4[(t3) & 0xff] & 0x000000ff) ^ rk[0]; - PUTU32(ct , s0); + PUTU32(ct, s0); s1 = (Te4[(t1 >> 24) ] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + (Te4[(t0) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + (Te4[(t1) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + (Te4[(t2) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); @@ -947,8 +944,7 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) /* * Decrypt the cipher into plain text */ -void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) -{ +void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) { unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv; const unsigned int *rk; int r; @@ -959,10 +955,14 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) * map byte array block to cipher state * and add initial round key: */ - v0 = GETU32(ct ); s0 = v0 ^ rk[0]; - v1 = GETU32(ct + 4); s1 = v1 ^ rk[1]; - v2 = GETU32(ct + 8); s2 = v2 ^ rk[2]; - v3 = GETU32(ct + 12); s3 = v3 ^ rk[3]; + v0 = GETU32(ct); + s0 = v0 ^ rk[0]; + v1 = GETU32(ct + 4); + s1 = v1 ^ rk[1]; + v2 = GETU32(ct + 8); + s2 = v2 ^ rk[2]; + v3 = GETU32(ct + 12); + s3 = v3 ^ rk[3]; /* * Nr - 1 full rounds: */ @@ -972,25 +972,25 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ - Td3[(s1 ) & 0xff] ^ + Td3[(s1) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ - Td3[(s2 ) & 0xff] ^ + Td3[(s2) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ - Td3[(s3 ) & 0xff] ^ + Td3[(s3) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ - Td3[(s0 ) & 0xff] ^ + Td3[(s0) & 0xff] ^ rk[7]; rk += 8; @@ -1002,25 +1002,25 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ - Td3[(t1 ) & 0xff] ^ + Td3[(t1) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ - Td3[(t2 ) & 0xff] ^ + Td3[(t2) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ - Td3[(t3 ) & 0xff] ^ + Td3[(t3) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ - Td3[(t0 ) & 0xff] ^ + Td3[(t0) & 0xff] ^ rk[3]; } /* @@ -1031,35 +1031,39 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) (Td4[(t0 >> 24) ] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + (Td4[(t1) & 0xff] & 0x000000ff) ^ rk[0]; s1 = (Td4[(t1 >> 24) ] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + (Td4[(t2) & 0xff] & 0x000000ff) ^ rk[1]; s2 = (Td4[(t2 >> 24) ] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + (Td4[(t3) & 0xff] & 0x000000ff) ^ rk[2]; s3 = (Td4[(t3 >> 24) ] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ - (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + (Td4[(t0) & 0xff] & 0x000000ff) ^ rk[3]; if (pCtx->Mode) { - s0 = s0 ^ iv[0]; iv[0] = v0; - s1 = s1 ^ iv[1]; iv[1] = v1; - s2 = s2 ^ iv[2]; iv[2] = v2; - s3 = s3 ^ iv[3]; iv[3] = v3; + s0 = s0 ^ iv[0]; + iv[0] = v0; + s1 = s1 ^ iv[1]; + iv[1] = v1; + s2 = s2 ^ iv[2]; + iv[2] = v2; + s3 = s3 ^ iv[3]; + iv[3] = v3; } - PUTU32(pt , s0); + PUTU32(pt, s0); PUTU32(pt + 4, s1); PUTU32(pt + 8, s2); PUTU32(pt + 12, s3); @@ -1072,8 +1076,7 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) /* * initialize AES context */ -int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) -{ +int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) { if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256)) return -1; @@ -1082,9 +1085,9 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in // initialize IV if (pIV != 0) { - pCtx->Iv[0] = GETU32(pIV ); - pCtx->Iv[1] = GETU32(pIV + 4 ); - pCtx->Iv[2] = GETU32(pIV + 8 ); + pCtx->Iv[0] = GETU32(pIV); + pCtx->Iv[1] = GETU32(pIV + 4); + pCtx->Iv[2] = GETU32(pIV + 8); pCtx->Iv[3] = GETU32(pIV + 12); } @@ -1097,8 +1100,7 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in /* * Encrypt plain text */ -int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) -{ +int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) { int i; if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0) @@ -1116,8 +1118,7 @@ int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsig /* * Decrypt cipher */ -int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) -{ +int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) { int i; if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0) @@ -1140,8 +1141,7 @@ int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsig #include -int main() -{ +int main() { AesCtx ctx; unsigned char iv[] = "INI VECTINI VECT"; unsigned char key[] = "This is a sample AESKey"; @@ -1149,22 +1149,22 @@ int main() // initialize context and encrypt data at one end - if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + if (AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) printf("init error\n"); - if (AesEncrypt(&ctx, databuf, databuf, sizeof(databuf) ) < 0) + if (AesEncrypt(&ctx, databuf, databuf, sizeof(databuf)) < 0) printf("error in encryption\n"); // initialize context and decrypt cipher at other end - if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) + if (AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0) printf("init error\n"); - if (AesDecrypt(&ctx, databuf, databuf, sizeof(databuf) ) < 0) + if (AesDecrypt(&ctx, databuf, databuf, sizeof(databuf)) < 0) printf("error in decryption\n"); printf("%s\n", databuf); return 0; } -#endif \ No newline at end of file +#endif diff --git a/armsrc/aes.h b/armsrc/aes.h index 6934d690c..aa9f0c582 100644 --- a/armsrc/aes.h +++ b/armsrc/aes.h @@ -8,11 +8,11 @@ // AES context structure typedef struct { - unsigned int Ek[60]; - unsigned int Dk[60]; - unsigned int Iv[4]; - unsigned char Nr; - unsigned char Mode; + unsigned int Ek[60]; + unsigned int Dk[60]; + unsigned int Iv[4]; + unsigned char Nr; + unsigned char Mode; } AesCtx; // key length in bytes @@ -31,4 +31,4 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen); int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen); -#endif \ No newline at end of file +#endif diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c6e6e0dee..23b55a23b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -19,166 +19,181 @@ #include "printf.h" #include "string.h" #include "legicrf.h" +#include "legicrfsim.h" #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" +#include "mifaresim.h" +#include "hitag.h" #define DEBUG 1 #ifdef WITH_LCD - #include "LCD.h" +#include "LCD.h" #endif #ifdef WITH_SMARTCARD #include "i2c.h" #endif -#ifdef WITH_FPC +#ifdef WITH_FPC_USART #include "usart.h" #endif +#ifdef WITH_FLASH +#include "flashmem.h" +#endif + //============================================================================= // A buffer where we can queue things up to be sent through the FPGA, for // any purpose (fake tag, as reader, whatever). We go MSB first, since that // 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 +#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]; int ToSendMax = -1; static int ToSendBit; struct common_area common_area __attribute__((section(".commonarea"))); +int button_status = BUTTON_NO_CLICK; void ToSendReset(void) { - ToSendMax = -1; - ToSendBit = 8; + ToSendMax = -1; + ToSendBit = 8; } void ToSendStuffBit(int b) { - if(ToSendBit >= 8) { - ToSendMax++; - ToSend[ToSendMax] = 0; - ToSendBit = 0; - } + if (ToSendBit >= 8) { + ToSendMax++; + ToSend[ToSendMax] = 0; + ToSendBit = 0; + } - if(b) - ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); + if (b) + ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); - ToSendBit++; + ToSendBit++; - if(ToSendMax >= sizeof(ToSend)) { - ToSendBit = 0; - DbpString("ToSendStuffBit overflowed!"); - } + if (ToSendMax >= sizeof(ToSend)) { + ToSendBit = 0; + DbpString("ToSendStuffBit overflowed!"); + } } +/* useful when debugging new protocol implementations like FeliCa void PrintToSendBuffer(void) { - DbpString("Printing ToSendBuffer:"); - Dbhexdump(ToSendMax, ToSend, 0); + DbpString("Printing ToSendBuffer:"); + Dbhexdump(ToSendMax, ToSend, 0); } +*/ void print_result(char *name, uint8_t *buf, size_t len) { - uint8_t *p = buf; - uint16_t tmp = len & 0xFFF0; + uint8_t *p = buf; + uint16_t tmp = len & 0xFFF0; - for(; p-buf < tmp; p += 16) { - Dbprintf("[%s: %02d/%02d] %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] - ); - } - if (len % 16 != 0) { - char s[46] = {0}; - char *sp = s; - for (; p-buf < len; p++ ) { - sprintf(sp, "%02x ", p[0] ); - sp += 3; - } - Dbprintf("[%s: %02d/%02d] %s", name, p-buf, len, s); - } + for (; p - buf < tmp; p += 16) { + Dbprintf("[%s: %02d/%02d] %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] + ); + } + if (len % 16 != 0) { + char s[46] = {0}; + char *sp = s; + for (; p - buf < len; p++) { + sprintf(sp, "%02x ", p[0]); + sp += 3; + } + Dbprintf("[%s: %02d/%02d] %s", name, p - buf, len, s); + } } //============================================================================= // Debug print functions, to go out over USB, to the usual PC-side client. //============================================================================= -void DbpStringEx(char *str, uint32_t cmd) { +void DbpStringEx(uint32_t flags, char *str) { #if DEBUG - uint8_t len = strlen(str); - cmd_send(CMD_DEBUG_PRINT_STRING, len, cmd, 0, (byte_t*)str, len); -#endif + struct { + uint16_t flag; + uint8_t buf[PM3_CMD_DATA_SIZE - sizeof(uint16_t)]; + } PACKED data; + data.flag = flags; + uint16_t len = MIN(strlen(str), sizeof(data.buf)); + memcpy(data.buf, str, len); + reply_ng(CMD_DEBUG_PRINT_STRING, PM3_SUCCESS, (uint8_t *)&data, sizeof(data.flag) + len); +#endif } void DbpString(char *str) { #if DEBUG - DbpStringEx(str, 0); -#endif + DbpStringEx(FLAG_LOG, str); +#endif } #if 0 void DbpIntegers(int x1, int x2, int x3) { - cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0); + reply_old(CMD_DEBUG_PRINT_INTEGERS, x1, x2, x3, 0, 0); } #endif -void DbprintfEx(uint32_t cmd, const char *fmt, ...) { +void DbprintfEx(uint32_t flags, const char *fmt, ...) { #if DEBUG - // should probably limit size here; oh well, let's just use a big buffer - char output_string[128] = {0x00}; - va_list ap; - va_start(ap, fmt); - kvsprintf(fmt, output_string, 10, ap); - va_end(ap); + // should probably limit size here; oh well, let's just use a big buffer + char output_string[128] = {0x00}; + va_list ap; + va_start(ap, fmt); + kvsprintf(fmt, output_string, 10, ap); + va_end(ap); - DbpStringEx(output_string, cmd); -#endif + DbpStringEx(flags, output_string); +#endif } void Dbprintf(const char *fmt, ...) { #if DEBUG - // should probably limit size here; oh well, let's just use a big buffer - char output_string[128] = {0x00}; - va_list ap; + // should probably limit size here; oh well, let's just use a big buffer + char output_string[128] = {0x00}; + va_list ap; - va_start(ap, fmt); - kvsprintf(fmt, output_string, 10, ap); - va_end(ap); + va_start(ap, fmt); + kvsprintf(fmt, output_string, 10, ap); + va_end(ap); - DbpString(output_string); -#endif + DbpString(output_string); +#endif } // prints HEX & ASCII void Dbhexdump(int len, uint8_t *d, bool bAsci) { #if DEBUG - int l=0, i; - char ascii[9]; - - while (len > 0) { + char ascii[9]; - l = (len > 8) ? 8 : len; - - memcpy(ascii, d, l); - ascii[l] = 0; - - // filter safe ascii - for (i=0; i 0) { + + int l = (len > 8) ? 8 : len; + + memcpy(ascii, d, l); + ascii[l] = 0; + + // filter safe ascii + for (int i = 0; i < l; i++) { if (ascii[i] < 32 || ascii[i] > 126) { ascii[i] = '.'; - } + } } - - if (bAsci) - Dbprintf("%-8s %*D", ascii, l, d, " "); - else - Dbprintf("%*D", l, d, " "); - - len -= 8; - d += 8; - } -#endif + + if (bAsci) + Dbprintf("%-8s %*D", ascii, l, d, " "); + else + Dbprintf("%*D", l, d, " "); + + len -= 8; + d += 8; + } +#endif } //----------------------------------------------------------------------------- @@ -188,128 +203,119 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) { //----------------------------------------------------------------------------- static uint16_t ReadAdc(int ch) { - // Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value. - // AMPL_HI is are 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%) + // Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value. + // AMPL_HI is are 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%) - 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 + 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 - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch); - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + 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))) {}; + while (!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) {}; - return (AT91C_BASE_ADC->ADC_CDR[ch] & 0x3FF); + return (AT91C_BASE_ADC->ADC_CDR[ch] & 0x3FF); } -// was static - merlok +// was static - merlok uint16_t AvgAdc(int ch) { - uint16_t a = 0; - for(uint8_t i = 0; i < 32; i++) - a += ReadAdc(ch); + uint16_t a = 0; + for (uint8_t i = 0; i < 32; i++) + a += ReadAdc(ch); - //division by 32 - return (a + 15) >> 5; + //division by 32 + return (a + 15) >> 5; } void MeasureAntennaTuning(void) { - uint8_t LF_Results[256]; - uint32_t i, adcval = 0, peak = 0, peakv = 0, peakf = 0; - uint32_t v_lf125 = 0, v_lf134 = 0, v_hf = 0; // in mV + uint8_t LF_Results[256]; + uint32_t i, peak = 0, peakv = 0, peakf = 0; + uint32_t v_lf125 = 0, v_lf134 = 0, v_hf = 0; // in mV - memset(LF_Results, 0, sizeof(LF_Results)); - LED_B_ON(); + memset(LF_Results, 0, sizeof(LF_Results)); + LED_B_ON(); -/* - * Sweeps the useful LF range of the proxmark from - * 46.8kHz (divisor=255) to 600kHz (divisor=19) and - * read the voltage in the antenna, the result left - * in the buffer is a graph which should clearly show - * 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(); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); - SpinDelay(20); - adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); + /* + * Sweeps the useful LF range of the proxmark from + * 46.8kHz (divisor=255) to 600kHz (divisor=19) and + * read the voltage in the antenna, the result left + * in the buffer is a graph which should clearly show + * 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(); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); + SpinDelay(20); + uint32_t adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); if (i == 95) v_lf125 = adcval; // voltage at 125Khz if (i == 89) v_lf134 = 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; - peakf = i; - peak = LF_Results[i]; - } - } - - LED_A_ON(); - // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(50); - v_hf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + LF_Results[i] = adcval >> 9; // scale int to fit in byte for graphing purposes + if (LF_Results[i] > peak) { + peakv = adcval; + peakf = i; + peak = LF_Results[i]; + } + } - // RDV40 will hit the roof, try other ADC channel used in that hardware revision. - if ( v_hf > MAX_ADC_HF_VOLTAGE-300 ) { - v_hf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; - } - - uint64_t arg0 = v_lf134; - arg0 <<= 32; - arg0 |= v_lf125; - - uint64_t arg2 = peakv; - arg2 <<= 32; - arg2 |= peakf; - - cmd_send(CMD_MEASURED_ANTENNA_TUNING, arg0, v_hf, arg2, LF_Results, 256); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_A_ON(); + // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(50); + v_hf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + + // RDV40 will hit the roof, try other ADC channel used in that hardware revision. + if (v_hf > MAX_ADC_HF_VOLTAGE - 300) { + v_hf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; + } + + uint64_t arg0 = v_lf134; + arg0 <<= 32; + arg0 |= v_lf125; + + uint64_t arg2 = peakv; + arg2 <<= 32; + arg2 |= peakf; + + reply_mix(CMD_MEASURE_ANTENNA_TUNING, arg0, v_hf, arg2, LF_Results, 256); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } -void MeasureAntennaTuningHf(void) { - uint16_t volt = 0; // in mV - // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(50); - volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; - bool use_high = ( volt > MAX_ADC_HF_VOLTAGE-300 ); - - while( !BUTTON_PRESS() ){ - SpinDelay(20); - if ( !use_high ) { - volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; - } else { - volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; - } - DbprintfEx(CMD_MEASURE_ANTENNA_TUNING_HF, "%u mV / %5u V", volt, (uint16_t)(volt/1000)); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("\n[+] cancelled"); +uint16_t MeasureAntennaTuningHfData(void) { + uint16_t volt = 0; // in mV + volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + bool use_high = (volt > MAX_ADC_HF_VOLTAGE - 300); + + if (!use_high) { + volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + } else { + volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; + } + return volt; } void ReadMem(int addr) { - const uint8_t *data = ((uint8_t *)addr); + const uint8_t *data = ((uint8_t *)addr); Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x", addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } @@ -319,143 +325,218 @@ 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 SendVersion(void) { - char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ - char VersionString[USB_CMD_DATA_SIZE] = { '\0' }; + char temp[PM3_CMD_DATA_SIZE - 12]; /* Limited data payload in USB packets */ + char VersionString[PM3_CMD_DATA_SIZE - 12] = { '\0' }; - /* 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; + /* 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; - strncat(VersionString, " [ ARM ]\n", sizeof(VersionString) - strlen(VersionString) - 1); - - if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) { - strcat(VersionString, "bootrom version information appears invalid\n"); - } else { - FormatVersionInformation(temp, sizeof(temp), " bootrom: ", bootrom_version); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); - } + strncat(VersionString, " [ ARM ]\n", sizeof(VersionString) - strlen(VersionString) - 1); - FormatVersionInformation(temp, sizeof(temp), " os: ", &version_information); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + if (bootrom_version < &_flash_start || bootrom_version >= &_flash_end) { + strcat(VersionString, "bootrom version information appears invalid\n"); + } else { + FormatVersionInformation(temp, sizeof(temp), " bootrom: ", bootrom_version); + strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + } - strncat(VersionString, "\n [ FPGA ]\n", sizeof(VersionString) - strlen(VersionString) - 1); - - for (int i = 0; i < fpga_bitstream_num; i++) { - strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1); - if (i < fpga_bitstream_num - 1) { - strncat(VersionString, "\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, 0, VersionString, strlen(VersionString)); + FormatVersionInformation(temp, sizeof(temp), " os: ", &version_information); + strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + + strncat(VersionString, "\n [ FPGA ]\n", sizeof(VersionString) - strlen(VersionString) - 1); + + for (int i = 0; i < fpga_bitstream_num; i++) { + strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1); + if (i < fpga_bitstream_num - 1) { + strncat(VersionString, "\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; + + struct p { + uint32_t id; + uint32_t section_size; + uint32_t versionstr_len; + char versionstr[PM3_CMD_DATA_SIZE - 12]; + } PACKED; + + struct p payload; + payload.id = *(AT91C_DBGU_CIDR); + payload.section_size = text_and_rodata_section_size + compressed_data_section_size; + payload.versionstr_len = strlen(VersionString); + memcpy(payload.versionstr, VersionString, strlen(VersionString)); + + reply_ng(CMD_VERSION, PM3_SUCCESS, (uint8_t *)&payload, 12 + strlen(VersionString)); } -// 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..."); +// measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. +// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the PacketCommandNG structure included. +void printConnSpeed(void) { + DbpString(_BLUE_("Transfer Speed")); + Dbprintf(" Sending packets to client..."); - #define USB_SPEED_TEST_MIN_TIME 1500 // in milliseconds - uint8_t *test_data = BigBuf_get_addr(); - uint32_t end_time; +#define CONN_SPEED_TEST_MIN_TIME 500 // in milliseconds + uint8_t *test_data = BigBuf_get_addr(); + uint32_t start_time = GetTickCount(); + uint32_t delta_time = 0; + uint32_t bytes_transferred = 0; - uint32_t start_time = end_time = GetTickCount(); - uint32_t bytes_transferred = 0; + LED_B_ON(); - LED_B_ON(); - 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; - } - LED_B_OFF(); + while (delta_time < CONN_SPEED_TEST_MIN_TIME) { + reply_ng(CMD_DOWNLOADED_BIGBUF, PM3_SUCCESS, test_data, PM3_CMD_DATA_SIZE); + bytes_transferred += PM3_CMD_DATA_SIZE; + delta_time = GetTickCountDelta(start_time); + } + LED_B_OFF(); - 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)); + Dbprintf(" Time elapsed............%dms", delta_time); + Dbprintf(" Bytes transferred.......%d", bytes_transferred); + Dbprintf(" Transfer Speed PM3 -> Client = " _YELLOW_("%d") "bytes/s", 1000 * bytes_transferred / delta_time); } - + /** * Prints runtime information about the PM3. **/ void SendStatus(void) { - BigBuf_print_status(); - Fpga_print_status(); - Flashmem_print_status(); -#ifdef WITH_SMARTCARD - I2C_print_status(); -#endif + BigBuf_print_status(); + Fpga_print_status(); +#ifdef WITH_FLASH + Flashmem_print_status(); +#endif +#ifdef WITH_SMARTCARD + I2C_print_status(); +#endif #ifdef WITH_LF - printConfig(); //LF Sampling config -#endif - printUSBSpeed(); - Dbprintf("Various"); - Dbprintf(" MF_DBGLEVEL.............%d", MF_DBGLEVEL); - Dbprintf(" ToSendMax...............%d", ToSendMax); - Dbprintf(" ToSendBit...............%d", ToSendBit); - Dbprintf(" ToSend BUFFERSIZE.......%d", TOSEND_BUFFER_SIZE); - printStandAloneModes(); - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); + printConfig(); // LF Sampling config + printT55xxConfig(); // LF T55XX Config +#endif + printConnSpeed(); + DbpString(_BLUE_("Various")); + Dbprintf(" DBGLEVEL................%d", DBGLEVEL); + Dbprintf(" ToSendMax...............%d", ToSendMax); + Dbprintf(" ToSendBit...............%d", ToSendBit); + Dbprintf(" ToSend BUFFERSIZE.......%d", TOSEND_BUFFER_SIZE); + DbpString(_BLUE_("Installed StandAlone Mode")); + ModInfo(); + +#ifdef WITH_FLASH + Flashmem_print_info(); +#endif + + reply_old(CMD_ACK, 1, 0, 0, 0, 0); +} + +void SendCapabilities(void) { + capabilities_t capabilities; + capabilities.version = CAPABILITIES_VERSION; + capabilities.via_fpc = reply_via_fpc; + capabilities.via_usb = reply_via_usb; + capabilities.baudrate = 0; // no real baudrate for USB-CDC +#ifdef WITH_FPC_USART + if (reply_via_fpc) + capabilities.baudrate = usart_baudrate; +#endif + +#ifdef WITH_FLASH + capabilities.compiled_with_flash = true; + capabilities.hw_available_flash = FlashInit(); +#else + capabilities.compiled_with_flash = false; + capabilities.hw_available_flash = false; +#endif +#ifdef WITH_SMARTCARD + capabilities.compiled_with_smartcard = true; + uint8_t maj, min; + capabilities.hw_available_smartcard = I2C_get_version(&maj, &min) == PM3_SUCCESS; +#else + capabilities.compiled_with_smartcard = false; + capabilities.hw_available_smartcard = false; +#endif +#ifdef WITH_FPC_USART + capabilities.compiled_with_fpc_usart = true; +#else + capabilities.compiled_with_fpc_usart = false; +#endif +#ifdef WITH_FPC_USART_DEV + capabilities.compiled_with_fpc_usart_dev = true; +#else + capabilities.compiled_with_fpc_usart_dev = false; +#endif +#ifdef WITH_FPC_USART_HOST + capabilities.compiled_with_fpc_usart_host = true; +#else + capabilities.compiled_with_fpc_usart_host = false; +#endif +#ifdef WITH_LF + capabilities.compiled_with_lf = true; +#else + capabilities.compiled_with_lf = false; +#endif +#ifdef WITH_HITAG + capabilities.compiled_with_hitag = true; +#else + capabilities.compiled_with_hitag = false; +#endif +#ifdef WITH_HFSNIFF + capabilities.compiled_with_hfsniff = true; +#else + capabilities.compiled_with_hfsniff = false; +#endif +#ifdef WITH_ISO14443a + capabilities.compiled_with_iso14443a = true; +#else + capabilities.compiled_with_iso14443a = false; +#endif +#ifdef WITH_ISO14443b + capabilities.compiled_with_iso14443b = true; +#else + capabilities.compiled_with_iso14443b = false; +#endif +#ifdef WITH_ISO15693 + capabilities.compiled_with_iso15693 = true; +#else + capabilities.compiled_with_iso15693 = false; +#endif +#ifdef WITH_FELICA + capabilities.compiled_with_felica = true; +#else + capabilities.compiled_with_felica = false; +#endif +#ifdef WITH_LEGICRF + capabilities.compiled_with_legicrf = true; +#else + capabilities.compiled_with_legicrf = false; +#endif +#ifdef WITH_ICLASS + capabilities.compiled_with_iclass = true; +#else + capabilities.compiled_with_iclass = false; +#endif +#ifdef WITH_LCD + capabilities.compiled_with_lcd = true; +#else + capabilities.compiled_with_lcd = false; +#endif + reply_ng(CMD_CAPABILITIES, PM3_SUCCESS, (uint8_t *)&capabilities, sizeof(capabilities)); } // Show some leds in a pattern to identify StandAlone mod is running void StandAloneMode(void) { - - DbpString("Stand-alone mode! No PC necessary."); - // Oooh pretty -- notify user we're in elite samy mode now - LED(LED_RED, 200); - LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); - LED(LED_RED, 200); - LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); - LED(LED_RED, 200); -} -// detection of which Standalone Modes is installed -// (iceman) -void printStandAloneModes(void) { - DbpString("Installed StandAlone Mods"); - -#if defined(WITH_LF_ICERUN) - DbpString(" LF sniff/clone/simulation - aka IceRun (iceman)"); -#endif -#if defined(WITH_HF_YOUNG) - DbpString(" HF Mifare sniff/simulation - (Craig Young)"); -#endif -#if defined(WITH_LF_SAMYRUN) - DbpString(" LF HID26 standalone - aka SamyRun (Samy Kamkar)"); -#endif -#if defined(WITH_LF_PROXBRUTE) - DbpString(" LF HID ProxII bruteforce - aka Proxbrute (Brad Antoniewicz)"); -#endif -#if defined(WITH_LF_HIDBRUTE) - DbpString(" LF HID corporate 1000 bruteforce - (Federico dotta & Maurizio Agazzini)"); -#endif -#if defined(WITH_HF_MATTYRUN) - DbpString(" HF Mifare sniff/clone - aka MattyRun (Matías A. Ré Medina)"); -#endif -#if defined(WITH_HF_COLIN) - DbpString(" HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN (Colin Brigato)"); -#endif - - //DbpString("Running "); - //Dbprintf(" Is Device attached to USB| %s", USB_ATTACHED() ? "Yes" : "No"); - //Dbprintf(" Is Device attached to FPC| %s", 0 ? "Yes" : "No"); - //Dbprintf(" Is USB_reconnect value | %d", GetUSBreconnect() ); - //Dbprintf(" Is USB_configured value | %d", GetUSBconfigured() ); - - //.. add your own standalone detection based on with compiler directive you are used. - // don't "reuse" the already taken ones, this will make things easier when trying to detect the different modes - // 2017-08-06 must adapt the makefile and have individual compilation flags for all mods - // + DbpString("Stand-alone mode! No PC necessary."); + + SpinDown(50); + SpinOff(50); + SpinUp(50); + SpinOff(50); + SpinDown(50); + SpinDelay(500); } /* @@ -480,990 +561,1368 @@ current compared to the maximum current detected. Basically, once you know what kind of external reader is present, it will help you spot the best location to place your antenna. You will probably not get some good results if there is a LF and a HF reader at the same place! :-) - -LIGHT SCHEME USED: */ -static const char LIGHT_SCHEME[] = { - 0x0, /* ---- | No field detected */ - 0x1, /* X--- | 14% of maximum current detected */ - 0x2, /* -X-- | 29% of maximum current detected */ - 0x4, /* --X- | 43% of maximum current detected */ - 0x8, /* ---X | 57% of maximum current detected */ - 0xC, /* --XX | 71% of maximum current detected */ - 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]); +#define LIGHT_LEVELS 20 -void ListenReaderField(int limit) { -#define LF_ONLY 1 -#define HF_ONLY 2 -#define REPORT_CHANGE 10 // report new values only if they have changed at least by REPORT_CHANGE +void ListenReaderField(uint8_t limit) { +#define LF_ONLY 1 +#define HF_ONLY 2 +#define REPORT_CHANGE 10 // report new values only if they have changed at least by REPORT_CHANGE - uint16_t lf_av, lf_av_new, lf_baseline = 0, lf_max; - uint16_t hf_av, hf_av_new, hf_baseline = 0, hf_max; - uint16_t mode = 1, display_val, display_max, i; + uint16_t lf_av = 0, lf_av_new, lf_baseline = 0, lf_max = 0; + uint16_t hf_av = 0, hf_av_new, hf_baseline = 0, hf_max = 0; + uint16_t mode = 1, display_val, display_max; + bool use_high = false; - // switch off FPGA - we don't want to measure our own signal - // 20180315 - iceman, why load this before and then turn off? - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // switch off FPGA - we don't want to measure our own signal + // 20180315 - iceman, why load this before and then turn off? + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LEDsoff(); - lf_av = lf_max = AvgAdc(ADC_CHAN_LF); + if (limit == LF_ONLY) { + lf_av = lf_max = AvgAdc(ADC_CHAN_LF); + Dbprintf("LF 125/134kHz Baseline: %dmV", (MAX_ADC_LF_VOLTAGE * lf_av) >> 10); + lf_baseline = lf_av; + } - if (limit != HF_ONLY) { - Dbprintf("LF 125/134kHz Baseline: %dmV", (MAX_ADC_LF_VOLTAGE * lf_av) >> 10); - lf_baseline = lf_av; - } + if (limit == HF_ONLY) { - hf_av = hf_max = AvgAdc(ADC_CHAN_HF); + hf_av = hf_max = AvgAdc(ADC_CHAN_HF); - // iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader. - // RDV40 will hit the roof, try other ADC channel used in that hardware revision. - bool use_high = ( ((MAX_ADC_HF_VOLTAGE * hf_max) >> 10) > MAX_ADC_HF_VOLTAGE-300 ); - if ( use_high ) { - hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); - } + // iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader. + // RDV40 will hit the roof, try other ADC channel used in that hardware revision. + use_high = (((MAX_ADC_HF_VOLTAGE * hf_max) >> 10) > MAX_ADC_HF_VOLTAGE - 300); + if (use_high) { + hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); + } - if (limit != LF_ONLY) { - Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10); - hf_baseline = hf_av; - } + Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10); + hf_baseline = hf_av; + } - for(;;) { - // Switch modes with button - if (BUTTON_PRESS()) { - SpinDelay(500); - switch (mode) { - case 1: - mode = 2; - DbpString("Signal Strength Mode"); - break; - case 2: - default: - DbpString("Stopped"); - LEDsoff(); - return; - break; - } - } - WDT_HIT(); + for (;;) { - if (limit != HF_ONLY) { - if(mode == 1) { - if (ABS(lf_av - lf_baseline) > REPORT_CHANGE) - LED_D_ON(); - else - LED_D_OFF(); - } + // Switch modes with button + if (BUTTON_PRESS()) { + SpinDelay(500); + switch (mode) { + case 1: + mode = 2; + DbpString("Signal Strength Mode"); + break; + case 2: + default: + DbpString("Stopped"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + return; + } + } + WDT_HIT(); - lf_av_new = AvgAdc(ADC_CHAN_LF); - // see if there's a significant change - if (ABS(lf_av - lf_av_new) > REPORT_CHANGE) { - Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10); - lf_av = lf_av_new; - if (lf_av > lf_max) - lf_max = lf_av; - } - } + if (limit == LF_ONLY) { + if (mode == 1) { + if (ABS(lf_av - lf_baseline) > REPORT_CHANGE) + LED_D_ON(); + else + LED_D_OFF(); + } - if (limit != LF_ONLY) { - if (mode == 1){ - if (ABS(hf_av - hf_baseline) > REPORT_CHANGE) - LED_B_ON(); - else - LED_B_OFF(); - } + lf_av_new = AvgAdc(ADC_CHAN_LF); + // see if there's a significant change + if (ABS(lf_av - lf_av_new) > REPORT_CHANGE) { + Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10); + lf_av = lf_av_new; + if (lf_av > lf_max) + lf_max = lf_av; + } + } - hf_av_new = (use_high) ? AvgAdc(ADC_CHAN_HF_RDV40) : AvgAdc(ADC_CHAN_HF); + if (limit == HF_ONLY) { + if (mode == 1) { + if (ABS(hf_av - hf_baseline) > REPORT_CHANGE) + LED_B_ON(); + else + LED_B_OFF(); + } - // see if there's a significant change - if(ABS(hf_av - hf_av_new) > REPORT_CHANGE) { - Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10); - hf_av = hf_av_new; - if (hf_av > hf_max) - hf_max = hf_av; - } - } + hf_av_new = (use_high) ? AvgAdc(ADC_CHAN_HF_RDV40) : AvgAdc(ADC_CHAN_HF); - if (mode == 2) { - if (limit == LF_ONLY) { - display_val = lf_av; - display_max = lf_max; - } else if (limit == HF_ONLY) { - display_val = hf_av; - display_max = hf_max; - } else { /* Pick one at random */ - if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) { - display_val = hf_av; - display_max = hf_max; - } else { - display_val = lf_av; - display_max = lf_max; - } - } - 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(); - if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF(); - break; - } - } - } - } + // see if there's a significant change + if (ABS(hf_av - hf_av_new) > REPORT_CHANGE) { + Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10); + hf_av = hf_av_new; + if (hf_av > hf_max) + hf_max = hf_av; + } + } + + if (mode == 2) { + if (limit == LF_ONLY) { + display_val = lf_av; + display_max = lf_max; + } else if (limit == HF_ONLY) { + display_val = hf_av; + display_max = hf_max; + } else { /* Pick one at random */ + if ((hf_max - hf_baseline) > (lf_max - lf_baseline)) { + display_val = hf_av; + display_max = hf_max; + } else { + display_val = lf_av; + display_max = lf_max; + } + } + + display_val = display_val * (4 * LIGHT_LEVELS) / MAX(1, display_max); + uint32_t duty_a = MIN(MAX(display_val, 0 * LIGHT_LEVELS), 1 * LIGHT_LEVELS) - 0 * LIGHT_LEVELS; + uint32_t duty_b = MIN(MAX(display_val, 1 * LIGHT_LEVELS), 2 * LIGHT_LEVELS) - 1 * LIGHT_LEVELS; + uint32_t duty_c = MIN(MAX(display_val, 2 * LIGHT_LEVELS), 3 * LIGHT_LEVELS) - 2 * LIGHT_LEVELS; + uint32_t duty_d = MIN(MAX(display_val, 3 * LIGHT_LEVELS), 4 * LIGHT_LEVELS) - 3 * LIGHT_LEVELS; + + // LED A + if (duty_a == 0) { + LED_A_OFF(); + } else if (duty_a == LIGHT_LEVELS) { + LED_A_ON(); + } else { + LED_A_ON(); + SpinDelay(duty_a); + LED_A_OFF(); + SpinDelay(LIGHT_LEVELS - duty_a); + } + + // LED B + if (duty_b == 0) { + LED_B_OFF(); + } else if (duty_b == LIGHT_LEVELS) { + LED_B_ON(); + } else { + LED_B_ON(); + SpinDelay(duty_b); + LED_B_OFF(); + SpinDelay(LIGHT_LEVELS - duty_b); + } + + // LED C + if (duty_c == 0) { + LED_C_OFF(); + } else if (duty_c == LIGHT_LEVELS) { + LED_C_ON(); + } else { + LED_C_ON(); + SpinDelay(duty_c); + LED_C_OFF(); + SpinDelay(LIGHT_LEVELS - duty_c); + } + + // LED D + if (duty_d == 0) { + LED_D_OFF(); + } else if (duty_d == LIGHT_LEVELS) { + LED_D_ON(); + } else { + LED_D_ON(); + SpinDelay(duty_d); + LED_D_OFF(); + SpinDelay(LIGHT_LEVELS - duty_d); + } + } + } } +static void PacketReceived(PacketCommandNG *packet) { + /* + if (packet->ng) { + Dbprintf("received NG frame with %d bytes payload, with command: 0x%04x", packet->length, cmd); + } else { + Dbprintf("received OLD frame of %d bytes, with command: 0x%04x and args: %d %d %d", packet->length, packet->cmd, packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + } + */ -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((sample_config *) c->d.asBytes); - break; - case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: { - uint32_t bits = SampleLF(c->arg[0], c->arg[1]); - cmd_send(CMD_ACK, bits, 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: { - uint32_t bits = SnoopLF(); - cmd_send(CMD_ACK, bits, 0, 0, 0, 0); - break; - } - case CMD_HID_DEMOD_FSK: { - uint32_t high, low; - CmdHIDdemodFSK(c->arg[0], &high, &low, 1); - break; - } - case CMD_HID_SIM_TAG: - CmdHIDsimTAG(c->arg[0], c->arg[1], 1); - 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]); - break; - case CMD_IO_DEMOD_FSK: { - uint32_t high, low; - CmdIOdemodFSK(c->arg[0], &high, &low, 1); - break; - } - case CMD_IO_CLONE_TAG: - CopyIOtoT55x7(c->arg[0], c->arg[1]); - break; - case CMD_EM410X_DEMOD: { - uint32_t high; - uint64_t low; - CmdEM410xdemod(c->arg[0], &high, &low, 1); - break; - } - case CMD_EM410X_WRITE_TAG: - WriteEM410x(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_READ_TI_TYPE: - ReadTItag(); - break; - case CMD_WRITE_TI_TYPE: - WriteTItag(c->arg[0],c->arg[1],c->arg[2]); - break; - case CMD_SIMULATE_TAG_125K: - LED_A_ON(); - SimulateTagLowFrequency(c->arg[0], c->arg[1], 1); - LED_A_OFF(); - break; - 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]); - break; - case CMD_INDALA_CLONE_TAG_L: - 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]); - 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]); - break; - case CMD_T55XX_RESET_READ: - T55xxResetRead(); - break; - case CMD_PCF7931_READ: - 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_EM4X_READ_WORD: - EM4xReadWord(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_EM4X_WRITE_WORD: - EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_AWID_DEMOD_FSK: { - uint32_t high, low; - // Set realtime AWID demodulation - CmdAWIDdemodFSK(c->arg[0], &high, &low, 1); - break; - } - case CMD_VIKING_CLONE_TAG: - CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]); + switch (packet->cmd) { + case CMD_QUIT_SESSION: + reply_via_fpc = false; + reply_via_usb = false; break; - case CMD_COTAG: - Cotag(c->arg[0]); - break; +#ifdef WITH_LF + case CMD_SET_LF_T55XX_CONFIG: { + setT55xxConfig(packet->oldarg[0], (t55xx_config *) packet->data.asBytes); + break; + } + case CMD_SET_LF_SAMPLING_CONFIG: { + setSamplingConfig((sample_config *) packet->data.asBytes); + break; + } + case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: { + struct p { + uint8_t silent; + uint32_t samples; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + uint32_t bits = SampleLF(payload->silent, payload->samples); + reply_ng(CMD_ACQUIRE_RAW_ADC_SAMPLES_125K, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits)); + break; + } + case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K: { + struct p { + uint32_t delay; + uint16_t ones; + uint16_t zeros; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + ModThenAcquireRawAdcSamples125k(payload->delay, payload->zeros, payload->ones, packet->data.asBytes + 8); + break; + } + case CMD_LF_SNIFF_RAW_ADC_SAMPLES: { + uint32_t bits = SniffLF(); + reply_mix(CMD_ACK, bits, 0, 0, 0, 0); + break; + } + case CMD_HID_DEMOD_FSK: { + uint32_t high, low; + CmdHIDdemodFSK(packet->oldarg[0], &high, &low, 1); + break; + } + case CMD_HID_SIM_TAG: { + CmdHIDsimTAG(packet->oldarg[0], packet->oldarg[1], 1); + break; + } + case CMD_FSK_SIM_TAG: { + lf_fsksim_t *payload = (lf_fsksim_t *)packet->data.asBytes; + CmdFSKsimTAG(payload->fchigh, payload->fclow, payload->separator, payload->clock, packet->length - sizeof(lf_fsksim_t), payload->data, true); + break; + } + case CMD_ASK_SIM_TAG: { + lf_asksim_t *payload = (lf_asksim_t *)packet->data.asBytes; + CmdASKsimTAG(payload->encoding, payload->invert, payload->separator, payload->clock, packet->length - sizeof(lf_asksim_t), payload->data, true); + break; + } + case CMD_PSK_SIM_TAG: { + lf_psksim_t *payload = (lf_psksim_t *)packet->data.asBytes; + CmdPSKsimTag(payload->carrier, payload->invert, payload->clock, packet->length - sizeof(lf_psksim_t), payload->data, true); + break; + } + case CMD_HID_CLONE_TAG: { + CopyHIDtoT55x7(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes[0]); + break; + } + case CMD_IO_DEMOD_FSK: { + uint32_t high, low; + CmdIOdemodFSK(packet->oldarg[0], &high, &low, 1); + break; + } + case CMD_IO_CLONE_TAG: { + CopyIOtoT55x7(packet->oldarg[0], packet->oldarg[1]); + break; + } + case CMD_EM410X_DEMOD: { + uint32_t high; + uint64_t low; + CmdEM410xdemod(packet->oldarg[0], &high, &low, 1); + break; + } + case CMD_EM410X_WRITE_TAG: { + WriteEM410x(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + break; + } + case CMD_READ_TI_TYPE: { + ReadTItag(); + break; + } + case CMD_WRITE_TI_TYPE: { + WriteTItag(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + break; + } + case CMD_SIMULATE_TAG_125K: { + LED_A_ON(); + struct p { + uint16_t len; + uint16_t gap; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + // length, start gap, led control + SimulateTagLowFrequency(payload->len, payload->gap, 1); + reply_ng(CMD_SIMULATE_TAG_125K, PM3_EOPABORTED, NULL, 0); + LED_A_OFF(); + break; + } + case CMD_LF_SIMULATE_BIDIR: { + SimulateTagLowFrequencyBidir(packet->oldarg[0], packet->oldarg[1]); + break; + } + case CMD_INDALA_CLONE_TAG: { + CopyIndala64toT55x7(packet->data.asDwords[0], packet->data.asDwords[1]); + break; + } + case CMD_INDALA_CLONE_TAG_L: { + CopyIndala224toT55x7( + packet->data.asDwords[0], packet->data.asDwords[1], packet->data.asDwords[2], packet->data.asDwords[3], + packet->data.asDwords[4], packet->data.asDwords[5], packet->data.asDwords[6] + ); + break; + } + case CMD_T55XX_READ_BLOCK: { + struct p { + uint32_t password; + uint8_t blockno; + uint8_t page; + bool pwdmode; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + T55xxReadBlock(payload->page, payload->pwdmode, false, payload->blockno, payload->password); + break; + } + case CMD_T55XX_WRITE_BLOCK: { + // uses NG format + T55xxWriteBlock(packet->data.asBytes); + break; + } + case CMD_T55XX_WAKEUP: { + T55xxWakeUp(packet->oldarg[0]); + break; + } + case CMD_T55XX_RESET_READ: { + T55xxResetRead(); + break; + } + case CMD_T55XX_CHKPWDS: { + T55xx_ChkPwds(); + break; + } + case CMD_PCF7931_READ: { + ReadPCF7931(); + break; + } + case CMD_PCF7931_WRITE: { + WritePCF7931( + packet->data.asBytes[0], packet->data.asBytes[1], packet->data.asBytes[2], packet->data.asBytes[3], + packet->data.asBytes[4], packet->data.asBytes[5], packet->data.asBytes[6], packet->data.asBytes[9], + packet->data.asBytes[7] - 128, packet->data.asBytes[8] - 128, + packet->oldarg[0], + packet->oldarg[1], + packet->oldarg[2] + ); + break; + } + case CMD_EM4X_READ_WORD: { + struct p { + uint32_t password; + uint8_t address; + uint8_t usepwd; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xReadWord(payload->address, payload->password, payload->usepwd); + break; + } + case CMD_EM4X_WRITE_WORD: { + struct p { + uint32_t password; + uint32_t data; + uint8_t address; + uint8_t usepwd; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd); + break; + } + case CMD_AWID_DEMOD_FSK: { + uint32_t high, low; + // Set realtime AWID demodulation + CmdAWIDdemodFSK(packet->oldarg[0], &high, &low, 1); + break; + } + case CMD_VIKING_CLONE_TAG: { + CopyVikingtoT55xx(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + break; + } + case CMD_COTAG: { + Cotag(packet->oldarg[0]); + break; + } #endif #ifdef WITH_HITAG - case CMD_SNOOP_HITAG: // Eavesdrop Hitag tag, args = type - SnoopHitag(c->arg[0]); - break; - case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content - 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],(byte_t*)c->d.asBytes); - break; - case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file - check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes); - break; - case CMD_READ_HITAG_S: //Reader for only Hitag S tags, args = key or challenge - ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); - 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; + case CMD_SNIFF_HITAG: { // Eavesdrop Hitag tag, args = type + SniffHitag(); + break; + } + case CMD_SIMULATE_HITAG: { // Simulate Hitag tag, args = memory content + SimulateHitagTag((bool)packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_READER_HITAG: { // Reader for Hitag tags, args = type and function + ReaderHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes); + break; + } + case CMD_SIMULATE_HITAG_S: { // Simulate Hitag s tag, args = memory content + SimulateHitagSTag((bool)packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_TEST_HITAGS_TRACES: { // Tests every challenge within the given file + check_challenges((bool)packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_READ_HITAG_S: { //Reader for only Hitag S tags, args = key or challenge + ReadHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes); + break; + } + case CMD_WR_HITAG_S: { //writer for Hitag tags args=data to write,page and key or challenge + if ((hitag_function)packet->oldarg[0] < 10) { + WritePageHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2]); + } else { + WriterHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2]); + } + break; + } #endif #ifdef WITH_ISO15693 - case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: - AcquireRawAdcSamplesIso15693(); - break; - 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; - 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_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: { + AcquireRawAdcSamplesIso15693(); + break; + } + case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693: { + RecordRawAdcSamplesIso15693(); + break; + } + case CMD_ISO_15693_COMMAND: { + DirectTag15693Command(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_ISO_15693_FIND_AFI: { + BruteforceIso15693Afi(packet->oldarg[0]); + break; + } + case CMD_READER_ISO_15693: { + ReaderIso15693(packet->oldarg[0]); + break; + } + case CMD_SIMTAG_ISO_15693: { + SimTagIso15693(packet->oldarg[0], packet->data.asBytes); + break; + } #endif #ifdef WITH_LEGICRF - case CMD_SIMULATE_TAG_LEGIC_RF: - LegicRfSimulate(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_WRITER_LEGIC_RF: - LegicRfWriter( c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_READER_LEGIC_RF: - LegicRfReader(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_LEGIC_INFO: - LegicRfInfo(); - break; - case CMD_LEGIC_ESET: - //----------------------------------------------------------------------------- - // 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. - //----------------------------------------------------------------------------- - // arg0 = offset - // arg1 = num of bytes - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - emlSet(c->d.asBytes, c->arg[0], c->arg[1]); - break; + case CMD_SIMULATE_TAG_LEGIC_RF: { + LegicRfSimulate(packet->oldarg[0]); + break; + } + case CMD_WRITER_LEGIC_RF: { + LegicRfWriter(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_READER_LEGIC_RF: { + LegicRfReader(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + break; + } + case CMD_LEGIC_INFO: { + LegicRfInfo(); + break; + } + case CMD_LEGIC_ESET: { + //----------------------------------------------------------------------------- + // 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. + //----------------------------------------------------------------------------- + // arg0 = offset + // arg1 = num of bytes + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]); + break; + } #endif #ifdef WITH_ISO14443b - case CMD_READ_SRI_TAG: - ReadSTMemoryIso14443b(c->arg[0]); - break; - case CMD_SNOOP_ISO_14443B: - SniffIso14443b(); - break; - case CMD_SIMULATE_TAG_ISO_14443B: - SimulateIso14443bTag(c->arg[0]); - break; - case CMD_ISO_14443B_COMMAND: - //SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); - SendRawCommand14443B_Ex(c); - break; + case CMD_READ_SRI_TAG: { + ReadSTMemoryIso14443b(packet->oldarg[0]); + break; + } + case CMD_SNIFF_ISO_14443B: { + SniffIso14443b(); + break; + } + case CMD_SIMULATE_TAG_ISO_14443B: { + SimulateIso14443bTag(packet->oldarg[0]); + break; + } + case CMD_ISO_14443B_COMMAND: { + //SendRawCommand14443B(packet->oldarg[0],packet->oldarg[1],packet->oldarg[2],packet->data.asBytes); + SendRawCommand14443B_Ex(packet); + break; + } #endif #ifdef WITH_FELICA - case CMD_FELICA_COMMAND: - felica_sendraw(c); - break; - case CMD_FELICA_LITE_SIM: - felica_sim_lite(c->arg[0]); + case CMD_FELICA_COMMAND: { + felica_sendraw(packet); break; - case CMD_FELICA_SNOOP: - felica_sniff(c->arg[0], c->arg[1]); + } + case CMD_FELICA_LITE_SIM: { + felica_sim_lite(packet->oldarg[0]); break; - case CMD_FELICA_LITE_DUMP: - felica_dump_lite_s(); + } + case CMD_FELICA_SNIFF: { + felica_sniff(packet->oldarg[0], packet->oldarg[1]); break; + } + case CMD_FELICA_LITE_DUMP: { + felica_dump_lite_s(); + break; + } #endif #ifdef WITH_ISO14443a - case CMD_SNOOP_ISO_14443a: - SniffIso14443a(c->arg[0]); - break; - case CMD_READER_ISO_14443a: - ReaderIso14443a(c); - break; - case CMD_SIMULATE_TAG_ISO_14443a: - SimulateIso14443aTag(c->arg[0], c->arg[1], c->d.asBytes); // ## Simulate iso14443a tag - pass tag type & UID - break; - case CMD_ANTIFUZZ_ISO_14443a: - iso14443a_antifuzz(c->arg[0]); - 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], c->arg[1], c->arg[2]); - 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); - 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; - 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_MIFAREU_WRITEBL_COMPAT: - //MifareUWriteBlockCompat(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; - case CMD_MIFARE_ACQUIRE_NONCES: - MifareAcquireNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_NESTED: - MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_CHKKEYS: { - MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - } - case CMD_MIFARE_CHKKEYS_FAST: { - MifareChkKeys_fast(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - } - case CMD_SIMULATE_MIFARE_CARD: - Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - - // emulator - case CMD_MIFARE_SET_DBGMODE: - MifareSetDbgLvl(c->arg[0]); - break; - case CMD_MIFARE_EML_MEMCLR: - MifareEMemClr(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_EML_MEMSET: - MifareEMemSet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_EML_MEMGET: - MifareEMemGet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - 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_CSETBLOCK: - MifareCSetBlock(c->arg[0], c->arg[1], c->d.asBytes); - break; - case CMD_MIFARE_CGETBLOCK: - MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes); - break; - case CMD_MIFARE_CIDENT: - MifareCIdent(); - break; - // mifare sniffer -// case CMD_MIFARE_SNIFFER: - //SniffMifare(c->arg[0]); -// break; - case CMD_MIFARE_SETMOD: - MifareSetMod(c->arg[0], c->d.asBytes); - break; - //mifare desfire - case CMD_MIFARE_DESFIRE_READBL: - break; - case CMD_MIFARE_DESFIRE_WRITEBL: - break; - case CMD_MIFARE_DESFIRE_AUTH1: - MifareDES_Auth1(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_DESFIRE_AUTH2: - //MifareDES_Auth2(c->arg[0],c->d.asBytes); - break; - case CMD_MIFARE_DES_READER: - //readermifaredes(c->arg[0], c->arg[1], c->d.asBytes); - break; - case CMD_MIFARE_DESFIRE_INFO: - MifareDesfireGetInformation(); - break; - case CMD_MIFARE_DESFIRE: - MifareSendCommand(c->arg[0], c->arg[1], c->d.asBytes); - break; - case CMD_MIFARE_COLLECT_NONCES: - break; - case CMD_MIFARE_NACK_DETECT: - DetectNACKbug(); - break; + case CMD_SNIFF_ISO_14443a: { + SniffIso14443a(packet->data.asBytes[0]); + break; + } + case CMD_READER_ISO_14443a: { + ReaderIso14443a(packet); + break; + } + case CMD_SIMULATE_TAG_ISO_14443a: { + struct p { + uint8_t tagtype; + uint8_t flags; + uint8_t uid[10]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + SimulateIso14443aTag(payload->tagtype, payload->flags, payload->uid); // ## Simulate iso14443a tag - pass tag type & UID + break; + } + case CMD_ANTIFUZZ_ISO_14443a: { + iso14443a_antifuzz(packet->oldarg[0]); + break; + } + case CMD_EPA_PACE_COLLECT_NONCE: { + EPA_PACE_Collect_Nonce(packet); + break; + } + case CMD_EPA_PACE_REPLAY: { + EPA_PACE_Replay(packet); + break; + } + case CMD_READER_MIFARE: { + ReaderMifare(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + break; + } + case CMD_MIFARE_READBL: { + mf_readblock_t *payload = (mf_readblock_t *)packet->data.asBytes; + MifareReadBlock(payload->blockno, payload->keytype, payload->key); + break; + } + case CMD_MIFAREU_READBL: { + MifareUReadBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFAREUC_AUTH: { + MifareUC_Auth(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_MIFAREU_READCARD: { + MifareUReadCard(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_MIFAREUC_SETPWD: { + MifareUSetPwd(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_MIFARE_READSC: { + MifareReadSector(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_WRITEBL: { + MifareWriteBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + //case CMD_MIFAREU_WRITEBL_COMPAT: { + //MifareUWriteBlockCompat(packet->oldarg[0], packet->data.asBytes); + //break; + //} + case CMD_MIFAREU_WRITEBL: { + MifareUWriteBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES: { + MifareAcquireEncryptedNonces(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_MIFARE_ACQUIRE_NONCES: { + MifareAcquireNonces(packet->oldarg[0], packet->oldarg[2]); + break; + } + case CMD_MIFARE_NESTED: { + MifareNested(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_MIFARE_CHKKEYS: { + MifareChkKeys(packet->data.asBytes); + break; + } + case CMD_MIFARE_CHKKEYS_FAST: { + MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_SIMULATE_MIFARE_CARD: { + struct p { + uint16_t flags; + uint8_t exitAfter; + uint8_t uid[10]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + Mifare1ksim(payload->flags, payload->exitAfter, payload->uid); + break; + } + // emulator + case CMD_SET_DBGMODE: { + DBGLEVEL = packet->data.asBytes[0]; + Dbprintf("Debug level: %d", DBGLEVEL); + reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0); + break; + } + case CMD_MIFARE_EML_MEMCLR: { + MifareEMemClr(); + reply_ng(CMD_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0); + break; + } + case CMD_MIFARE_EML_MEMSET: { + struct p { + uint8_t blockno; + uint8_t blockcnt; + uint8_t blockwidth; + uint8_t data[]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareEMemSet(payload->blockno, payload->blockcnt, payload->blockwidth, payload->data); + break; + } + case CMD_MIFARE_EML_MEMGET: { + struct p { + uint8_t blockno; + uint8_t blockcnt; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareEMemGet(payload->blockno, payload->blockcnt); + break; + } + case CMD_MIFARE_EML_CARDLOAD: { + MifareECardLoad(packet->oldarg[0], packet->oldarg[1]); + break; + } + // Work with "magic Chinese" card + case CMD_MIFARE_CSETBLOCK: { + MifareCSetBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_CGETBLOCK: { + MifareCGetBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_CIDENT: { + MifareCIdent(); + break; + } + // mifare sniffer +// case CMD_MIFARE_SNIFFER: { +// SniffMifare(packet->oldarg[0]); +// break; +// } + case CMD_MIFARE_SETMOD: { + MifareSetMod(packet->data.asBytes); + break; + } + //mifare desfire + case CMD_MIFARE_DESFIRE_READBL: { + break; + } + case CMD_MIFARE_DESFIRE_WRITEBL: { + break; + } + case CMD_MIFARE_DESFIRE_AUTH1: { + MifareDES_Auth1(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_MIFARE_DESFIRE_AUTH2: { + //MifareDES_Auth2(packet->oldarg[0],packet->data.asBytes); + break; + } + case CMD_MIFARE_DES_READER: { + //readermifaredes(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_DESFIRE_INFO: { + MifareDesfireGetInformation(); + break; + } + case CMD_MIFARE_DESFIRE: { + MifareSendCommand(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_MIFARE_COLLECT_NONCES: { + break; + } + case CMD_MIFARE_NACK_DETECT: { + DetectNACKbug(); + break; + } #endif #ifdef WITH_ICLASS - // Makes use of ISO14443a FPGA Firmware - case CMD_SNOOP_ICLASS: - SniffIClass(); - break; - case CMD_SIMULATE_TAG_ICLASS: - SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_READER_ICLASS: - ReaderIClass(c->arg[0]); - break; - case CMD_READER_ICLASS_REPLAY: - ReaderIClass_Replay(c->arg[0], c->d.asBytes); - break; - case CMD_ICLASS_EML_MEMSET: - //iceman, should call FPGADOWNLOAD before, since it corrupts BigBuf - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - 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_READCHECK: // auth step 1 - iClass_ReadCheck(c->arg[0], c->arg[1]); - break; - case CMD_ICLASS_READBLOCK: - iClass_ReadBlk(c->arg[0]); - break; - case CMD_ICLASS_AUTHENTICATION: //check - iClass_Authentication(c->d.asBytes); - break; - case CMD_ICLASS_CHECK_KEYS: - iClass_Authentication_fast(c->arg[0], c->arg[1], c->d.asBytes); - 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; + // Makes use of ISO14443a FPGA Firmware + case CMD_SNIFF_ICLASS: { + SniffIClass(); + break; + } + case CMD_SIMULATE_TAG_ICLASS: { + SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); + break; + } + case CMD_READER_ICLASS: { + ReaderIClass(packet->oldarg[0]); + break; + } + case CMD_READER_ICLASS_REPLAY: { + ReaderIClass_Replay(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_ICLASS_EML_MEMSET: { + //iceman, should call FPGADOWNLOAD before, since it corrupts BigBuf + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]); + break; + } + case CMD_ICLASS_WRITEBLOCK: { + iClass_WriteBlock(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_ICLASS_READCHECK: { // auth step 1 + iClass_ReadCheck(packet->oldarg[0], packet->oldarg[1]); + break; + } + case CMD_ICLASS_READBLOCK: { + iClass_ReadBlk(packet->oldarg[0]); + break; + } + case CMD_ICLASS_AUTHENTICATION: { //check + iClass_Authentication(packet->data.asBytes); + break; + } + case CMD_ICLASS_CHECK_KEYS: { + iClass_Authentication_fast(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_ICLASS_DUMP: { + iClass_Dump(packet->oldarg[0], packet->oldarg[1]); + break; + } + case CMD_ICLASS_CLONE: { + iClass_Clone(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } #endif -#ifdef WITH_HFSNOOP - case CMD_HF_SNIFFER: - HfSnoop(c->arg[0], c->arg[1]); - break; +#ifdef WITH_HFSNIFF + case CMD_HF_SNIFFER: { + HfSniff(packet->oldarg[0], packet->oldarg[1]); + break; + } #endif #ifdef WITH_SMARTCARD - case CMD_SMART_ATR: { - SmartCardAtr(); - break; - } - case CMD_SMART_SETBAUD:{ - SmartCardSetBaud(c->arg[0]); - break; - } - case CMD_SMART_SETCLOCK:{ - SmartCardSetClock(c->arg[0]); - break; - } - case CMD_SMART_RAW: { - SmartCardRaw(c->arg[0], c->arg[1], c->d.asBytes); + case CMD_SMART_ATR: { + SmartCardAtr(); + break; + } + case CMD_SMART_SETBAUD: { + SmartCardSetBaud(packet->oldarg[0]); + break; + } + case CMD_SMART_SETCLOCK: { + SmartCardSetClock(packet->oldarg[0]); + break; + } + case CMD_SMART_RAW: { + SmartCardRaw(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } + case CMD_SMART_UPLOAD: { + // upload file from client + uint8_t *mem = BigBuf_get_addr(); + memcpy(mem + packet->oldarg[0], packet->data.asBytes, PM3_CMD_DATA_SIZE); + reply_old(CMD_ACK, 1, 0, 0, 0, 0); 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 - -#ifdef WITH_FPC - case CMD_FPC_SEND: { -// char header[] = {"*** Iceman Usart ***"}; -// uint32_t res = usart_writebuffer((uint8_t *)header, sizeof(header), 10000); - - //temp++; - uint8_t got = usart_read(10000); - if ( got > 0 ) { - Dbprintf("got %02x", got); - usart_write(got, 10000); - } - cmd_send(CMD_ACK,0,0,0,0,0); - break; - } + SmartCardUpgrade(packet->oldarg[0]); + break; + } #endif - case CMD_BUFF_CLEAR: - BigBuf_Clear(); - BigBuf_free(); - break; - case CMD_MEASURE_ANTENNA_TUNING: - MeasureAntennaTuning(); - break; +#ifdef WITH_FPC_USART + case CMD_USART_TX: { + LED_B_ON(); + usart_writebuffer_sync(packet->data.asBytes, packet->length); + reply_ng(CMD_USART_TX, PM3_SUCCESS, NULL, 0); + LED_B_OFF(); + break; + } + case CMD_USART_RX: { + LED_B_ON(); + struct p { + uint32_t waittime; + } PACKED; + struct p *payload = (struct p *) &packet->data.asBytes; + uint16_t available; + uint16_t pre_available = 0; + uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); + uint32_t wait = payload->waittime; + uint32_t ti = GetTickCount(); + while (true) { + WaitMS(50); + available = usart_rxdata_available(); + if (available > pre_available) { + // When receiving data, reset timer and shorten timeout + ti = GetTickCount(); + wait = 50; + pre_available = available; + continue; + } + // We stop either after waittime if no data or 50ms after last data received + if (GetTickCountDelta(ti) > wait) + break; + } + if (available > 0) { + uint16_t len = usart_read_ng(dest, available); + reply_ng(CMD_USART_RX, PM3_SUCCESS, dest, len); + } else { + reply_ng(CMD_USART_RX, PM3_ENODATA, NULL, 0); + } + BigBuf_free(); + LED_B_OFF(); + break; + } + case CMD_USART_TXRX: { + LED_B_ON(); + struct p { + uint32_t waittime; + uint8_t data[]; + } PACKED; + struct p *payload = (struct p *) &packet->data.asBytes; + usart_writebuffer_sync(payload->data, packet->length - sizeof(payload)); + uint16_t available; + uint16_t pre_available = 0; + uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); + uint32_t wait = payload->waittime; + uint32_t ti = GetTickCount(); + while (true) { + WaitMS(50); + available = usart_rxdata_available(); + if (available > pre_available) { + // When receiving data, reset timer and shorten timeout + ti = GetTickCount(); + wait = 50; + pre_available = available; + continue; + } + // We stop either after waittime if no data or 50ms after last data received + if (GetTickCountDelta(ti) > wait) + break; + } + if (available > 0) { + uint16_t len = usart_read_ng(dest, available); + reply_ng(CMD_USART_TXRX, PM3_SUCCESS, dest, len); + } else { + reply_ng(CMD_USART_TXRX, PM3_ENODATA, NULL, 0); + } + BigBuf_free(); + LED_B_OFF(); + break; + } + case CMD_USART_CONFIG: { + struct p { + uint32_t baudrate; + uint8_t parity; + } PACKED; + struct p *payload = (struct p *) &packet->data.asBytes; + usart_init(payload->baudrate, payload->parity); + reply_ng(CMD_USART_CONFIG, PM3_SUCCESS, NULL, 0); + break; + } +#endif + case CMD_BUFF_CLEAR: { + BigBuf_Clear(); + BigBuf_free(); + break; + } + case CMD_MEASURE_ANTENNA_TUNING: { + MeasureAntennaTuning(); + break; + } + case CMD_MEASURE_ANTENNA_TUNING_HF: { + if (packet->length != 1) + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_EINVARG, NULL, 0); + switch (packet->data.asBytes[0]) { + case 1: // MEASURE_ANTENNA_TUNING_HF_START + // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, NULL, 0); + break; + case 2: + if (button_status == BUTTON_SINGLE_CLICK) + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_EOPABORTED, NULL, 0); + uint16_t volt = MeasureAntennaTuningHfData(); + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, (uint8_t *)&volt, sizeof(volt)); + break; + case 3: + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, NULL, 0); + break; + default: + reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_EINVARG, NULL, 0); + break; + } + break; + } + case CMD_LISTEN_READER_FIELD: { + if (packet->length != sizeof(uint8_t)) + break; + ListenReaderField(packet->data.asBytes[0]); + break; + } + 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 + break; + } + case CMD_DOWNLOAD_BIGBUF: { + LED_B_ON(); + uint8_t *mem = BigBuf_get_addr(); + uint32_t startidx = packet->oldarg[0]; + uint32_t numofbytes = packet->oldarg[1]; - case CMD_MEASURE_ANTENNA_TUNING_HF: - MeasureAntennaTuningHf(); - break; + // arg0 = startindex + // arg1 = length bytes to transfer + // arg2 = BigBuf tracelen + //Dbprintf("transfer to client parameters: %" PRIu32 " | %" PRIu32 " | %" PRIu32, startidx, numofbytes, packet->oldarg[2]); - case CMD_LISTEN_READER_FIELD: - ListenReaderField(c->arg[0]); - break; - - 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 - break; + for (size_t i = 0; i < numofbytes; i += PM3_CMD_DATA_SIZE) { + size_t len = MIN((numofbytes - i), PM3_CMD_DATA_SIZE); + int result = reply_old(CMD_DOWNLOADED_BIGBUF, i, len, BigBuf_get_traceLen(), mem + startidx + i, len); + if (result != PM3_SUCCESS) + Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result); + } + // Trigger a finish downloading signal with an ACK frame + // iceman, when did sending samplingconfig array got attached here?!? + // arg0 = status of download transfer + // arg1 = RFU + // arg2 = tracelen? + // asbytes = samplingconfig array + reply_old(CMD_ACK, 1, 0, BigBuf_get_traceLen(), getSamplingConfig(), sizeof(sample_config)); + LED_B_OFF(); + break; + } #ifdef WITH_LF - case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: { - LED_B_ON(); - uint8_t *mem = BigBuf_get_addr(); - bool isok = false; - size_t len = 0; - uint32_t startidx = c->arg[0]; - uint32_t numofbytes = c->arg[1]; - // arg0 = startindex - // arg1 = length bytes to transfer - // arg2 = BigBuf tracelen - //Dbprintf("transfer to client parameters: %" PRIu32 " | %" PRIu32 " | %" PRIu32, startidx, numofbytes, c->arg[2]); - - for(size_t i = 0; i < numofbytes; i += USB_CMD_DATA_SIZE) { - len = MIN( (numofbytes - i), USB_CMD_DATA_SIZE); - isok = cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, i, len, BigBuf_get_traceLen(), mem + startidx + i, len); - if (!isok) - Dbprintf("transfer to client failed :: | bytes between %d - %d (%d)", i, i+len, len); - } - // Trigger a finish downloading signal with an ACK frame - // iceman, when did sending samplingconfig array got attached here?!? - // arg0 = status of download transfer - // arg1 = RFU - // arg2 = tracelen? - // asbytes = samplingconfig array - cmd_send(CMD_ACK, 1, 0, BigBuf_get_traceLen(), getSamplingConfig(), sizeof(sample_config)); - LED_B_OFF(); - break; - } -#endif - case CMD_UPLOAD_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 - #define FPGA_LF 1 - if ( c->arg[1] == FPGA_LF ) - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - else - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - 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_DOWNLOAD_EML_BIGBUF: { - LED_B_ON(); - uint8_t *mem = BigBuf_get_EM_addr(); - bool isok = false; - size_t len = 0; - uint32_t startidx = c->arg[0]; - uint32_t numofbytes = c->arg[1]; + case CMD_UPLOAD_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 + // flag = + // b0 0 skip + // 1 clear bigbuff + struct p { + uint8_t flag; + uint16_t offset; + uint8_t *data; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; - // arg0 = startindex - // arg1 = length bytes to transfer - // arg2 = RFU - //Dbprintf("transfer to client parameters: %" PRIu32 " | %" PRIu32 " | %" PRIu32, startidx, numofbytes, c->arg[2]); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - for (size_t i = 0; i < numofbytes; i += USB_CMD_DATA_SIZE) { - len = MIN((numofbytes - i), USB_CMD_DATA_SIZE); - isok = cmd_send(CMD_DOWNLOADED_EML_BIGBUF, i, len, 0, mem + startidx + i, len); - if (!isok) - Dbprintf("transfer to client failed :: | bytes between %d - %d (%d)", i, i+len, len); - } - // Trigger a finish downloading signal with an ACK frame - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - LED_B_OFF(); - break; - } - case CMD_READ_MEM: - ReadMem(c->arg[0]); - break; -#ifdef WITH_FLASH - case CMD_READ_FLASH_MEM: { + if ((payload->flag & 0x1) == 0x1) { + BigBuf_Clear_ext(false); + BigBuf_free(); + } - LED_B_ON(); - uint16_t isok = 0; - uint32_t startidx = c->arg[0]; - uint16_t len = c->arg[1]; - - Dbprintf("FlashMem read | %d - %d", startidx, len); - - size_t size = MIN(USB_CMD_DATA_SIZE, len); - - uint8_t *mem = BigBuf_malloc(size); - - for(size_t i = 0; i < len; i += size) { - len = MIN((len - i), size); - - memset(mem, 0, len); - - Dbprintf("FlashMem reading | %d | %d | %d", startidx + i, i, len); - - isok = Flash_ReadData(startidx + i, mem, len); - if ( isok == len ) { - print_result("Chunk: ", mem, len); - } else { - Dbprintf("FlashMem reading failed | %d | %d", len, isok); - break; - } - } - LED_B_OFF(); - break; - } - case CMD_WRITE_FLASH_MEM: { - LED_B_ON(); - uint8_t isok = 0; - uint16_t res = 0; - uint32_t startidx = c->arg[0]; - uint16_t len = c->arg[1]; - uint8_t* data = c->d.asBytes; - - uint32_t tmp = startidx + len; - - // inside 256b page? - if ( (tmp & 0xFF) != 0) { - - // is offset+len larger than a page - tmp = (startidx & 0xFF ) + len; - if (tmp > 0xFF ) { - - // data spread over two pages. - - // offset xxxx10, - uint8_t first_len = (~startidx & 0xFF)+1; - - // first mem page - res = Flash_WriteData(startidx, data, first_len); - - // second mem page - res = Flash_WriteData(startidx + first_len, data + first_len, len - first_len); - - isok = (res == (len - first_len)) ? 1 : 0; - - } else { - res = Flash_WriteData(startidx, data, len); - isok = (res == len) ? 1 : 0; - } - } else { - res = Flash_WriteData(startidx, data, len); - isok = (res == len) ? 1 : 0; - } - - cmd_send(CMD_ACK, isok, 0, 0, 0, 0); - LED_B_OFF(); - break; - } - case CMD_WIPE_FLASH_MEM: { - LED_B_ON(); - uint8_t page = c->arg[0]; - uint8_t initalwipe = c->arg[1]; - bool isok = false; - if ( initalwipe ) { - isok = Flash_WipeMemory(); - cmd_send(CMD_ACK, isok, 0, 0, 0, 0); - LED_B_OFF(); - break; - } - if ( page < 3) - isok = Flash_WipeMemoryPage(page); - - cmd_send(CMD_ACK, isok, 0, 0, 0, 0); - LED_B_OFF(); - break; - } - case CMD_DOWNLOAND_FLASH_MEM: { - - LED_B_ON(); - uint8_t *mem = BigBuf_malloc(USB_CMD_DATA_SIZE); - bool isok = false; - size_t len = 0; - uint32_t startidx = c->arg[0]; - uint32_t numofbytes = c->arg[1]; - // arg0 = startindex - // arg1 = length bytes to transfer - // arg2 = RFU - for (size_t i = 0; i < numofbytes; i += USB_CMD_DATA_SIZE) { - len = MIN((numofbytes - i), USB_CMD_DATA_SIZE); - - isok = Flash_ReadData(startidx + i, mem, len); - if (!isok ) - Dbprintf("reading flash memory failed :: | bytes between %d - %d", i, len); - - isok = cmd_send(CMD_DOWNLOADED_FLASHMEM, i, len, 0, mem, len); - if (!isok) - Dbprintf("transfer to client failed :: | bytes between %d - %d (%d)", i, i+len, len); - } - - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - LED_B_OFF(); - break; - } - case CMD_INFO_FLASH_MEM: { - - LED_B_ON(); - rdv40_validation_t *info = (rdv40_validation_t*)BigBuf_malloc( sizeof(rdv40_validation_t) ); - - bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET, info->signature, FLASH_MEM_SIGNATURE_LEN); - - if (FlashInit()) { - Flash_UniqueID( info->flashid); - FlashStop(); - } - cmd_send(CMD_ACK, isok, 0, 0, info, sizeof(rdv40_validation_t)); - BigBuf_free(); - - LED_B_OFF(); - break; - } + uint8_t *mem = BigBuf_get_addr(); + memcpy(mem + payload->offset, &payload->data, PM3_CMD_DATA_SIZE - 3); + reply_ng(CMD_UPLOAD_SIM_SAMPLES_125K, PM3_SUCCESS, NULL, 0); + break; + } #endif - case CMD_SET_LF_DIVISOR: - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]); - break; + case CMD_DOWNLOAD_EML_BIGBUF: { + LED_B_ON(); + uint8_t *mem = BigBuf_get_EM_addr(); + uint32_t startidx = packet->oldarg[0]; + uint32_t numofbytes = packet->oldarg[1]; - case CMD_SET_ADC_MUX: - switch(c->arg[0]) { - case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break; - case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break; -#ifndef WITH_FPC - case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break; - case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break; + // arg0 = startindex + // arg1 = length bytes to transfer + // arg2 = RFU + + for (size_t i = 0; i < numofbytes; i += PM3_CMD_DATA_SIZE) { + size_t len = MIN((numofbytes - i), PM3_CMD_DATA_SIZE); + int result = reply_old(CMD_DOWNLOADED_EML_BIGBUF, i, len, 0, mem + startidx + i, len); + if (result != PM3_SUCCESS) + Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result); + } + // Trigger a finish downloading signal with an ACK frame + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + LED_B_OFF(); + break; + } + case CMD_READ_MEM: { + if (packet->length != sizeof(uint32_t)) + break; + ReadMem(packet->data.asDwords[0]); + break; + } +#ifdef WITH_FLASH + case CMD_FLASHMEM_SET_SPIBAUDRATE: { + FlashmemSetSpiBaudrate(packet->oldarg[0]); + break; + } + case CMD_FLASHMEM_READ: { + LED_B_ON(); + uint32_t startidx = packet->oldarg[0]; + uint16_t len = packet->oldarg[1]; + + Dbprintf("FlashMem read | %d - %d | ", startidx, len); + + size_t size = MIN(PM3_CMD_DATA_SIZE, len); + + if (!FlashInit()) { + break; + } + + uint8_t *mem = BigBuf_malloc(size); + + for (size_t i = 0; i < len; i += size) { + len = MIN((len - i), size); + + Dbprintf("FlashMem reading | %d | %d | %d |", startidx + i, i, len); + uint16_t isok = Flash_ReadDataCont(startidx + i, mem, len); + if (isok == len) { + print_result("Chunk: ", mem, len); + } else { + Dbprintf("FlashMem reading failed | %d | %d", len, isok); + break; + } + } + BigBuf_free(); + FlashStop(); + LED_B_OFF(); + break; + } + case CMD_FLASHMEM_WRITE: { + LED_B_ON(); + uint8_t isok = 0; + uint16_t res = 0; + uint32_t startidx = packet->oldarg[0]; + uint16_t len = packet->oldarg[1]; + uint8_t *data = packet->data.asBytes; + + uint32_t tmp = startidx + len; + + if (!FlashInit()) { + break; + } + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + + if (startidx == DEFAULT_T55XX_KEYS_OFFSET) { + Flash_Erase4k(3, 0xC); + } else if (startidx == DEFAULT_MF_KEYS_OFFSET) { + Flash_Erase4k(3, 0x9); + Flash_Erase4k(3, 0xA); + } else if (startidx == DEFAULT_ICLASS_KEYS_OFFSET) { + Flash_Erase4k(3, 0xB); + } + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + + // inside 256b page? + if ((tmp & 0xFF) != 0) { + + // is offset+len larger than a page + tmp = (startidx & 0xFF) + len; + if (tmp > 0xFF) { + + // data spread over two pages. + + // offset xxxx10, + uint8_t first_len = (~startidx & 0xFF) + 1; + + // first mem page + res = Flash_WriteDataCont(startidx, data, first_len); + + isok = (res == first_len) ? 1 : 0; + + // second mem page + res = Flash_WriteDataCont(startidx + first_len, data + first_len, len - first_len); + + isok &= (res == (len - first_len)) ? 1 : 0; + + } else { + res = Flash_WriteDataCont(startidx, data, len); + isok = (res == len) ? 1 : 0; + } + } else { + res = Flash_WriteDataCont(startidx, data, len); + isok = (res == len) ? 1 : 0; + } + FlashStop(); + + reply_old(CMD_ACK, isok, 0, 0, 0, 0); + LED_B_OFF(); + break; + } + case CMD_FLASHMEM_WIPE: { + LED_B_ON(); + uint8_t page = packet->oldarg[0]; + uint8_t initalwipe = packet->oldarg[1]; + bool isok = false; + if (initalwipe) { + isok = Flash_WipeMemory(); + reply_old(CMD_ACK, isok, 0, 0, 0, 0); + LED_B_OFF(); + break; + } + if (page < 3) + isok = Flash_WipeMemoryPage(page); + + reply_old(CMD_ACK, isok, 0, 0, 0, 0); + LED_B_OFF(); + break; + } + case CMD_FLASHMEM_DOWNLOAD: { + + LED_B_ON(); + uint8_t *mem = BigBuf_malloc(PM3_CMD_DATA_SIZE); + uint32_t startidx = packet->oldarg[0]; + uint32_t numofbytes = packet->oldarg[1]; + // arg0 = startindex + // arg1 = length bytes to transfer + // arg2 = RFU + + if (!FlashInit()) { + break; + } + + for (size_t i = 0; i < numofbytes; i += PM3_CMD_DATA_SIZE) { + size_t len = MIN((numofbytes - i), PM3_CMD_DATA_SIZE); + + bool isok = Flash_ReadDataCont(startidx + i, mem, len); + if (!isok) + Dbprintf("reading flash memory failed :: | bytes between %d - %d", i, len); + + isok = reply_old(CMD_FLASHMEM_DOWNLOADED, i, len, 0, mem, len); + if (isok != 0) + Dbprintf("transfer to client failed :: | bytes between %d - %d", i, len); + } + FlashStop(); + + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + BigBuf_free(); + LED_B_OFF(); + break; + } + case CMD_FLASHMEM_INFO: { + + LED_B_ON(); + rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_malloc(sizeof(rdv40_validation_t)); + + bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET, info->signature, FLASH_MEM_SIGNATURE_LEN); + + if (FlashInit()) { + Flash_UniqueID(info->flashid); + FlashStop(); + } + reply_old(CMD_ACK, isok, 0, 0, info, sizeof(rdv40_validation_t)); + BigBuf_free(); + + LED_B_OFF(); + break; + } #endif - } - break; - - case CMD_VERSION: - SendVersion(); - break; - case CMD_STATUS: - SendStatus(); - break; - case CMD_PING: - cmd_send(CMD_ACK,0,0,0,0,0); - break; + case CMD_SET_LF_DIVISOR: { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, packet->data.asBytes[0]); + break; + } + case CMD_SET_ADC_MUX: { + switch (packet->data.asBytes[0]) { + case 0: + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + break; + case 2: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + break; +#ifndef WITH_FPC_USART + case 1: + SetAdcMuxFor(GPIO_MUXSEL_LORAW); + break; + case 3: + SetAdcMuxFor(GPIO_MUXSEL_HIRAW); + break; +#endif + } + break; + } + case CMD_VERSION: { + SendVersion(); + break; + } + case CMD_STATUS: { + SendStatus(); + break; + } + case CMD_CAPABILITIES: { + SendCapabilities(); + break; + } + case CMD_PING: { + reply_ng(CMD_PING, PM3_SUCCESS, packet->data.asBytes, packet->length); + break; + } #ifdef WITH_LCD - case CMD_LCD_RESET: - LCDReset(); - break; - case CMD_LCD: - LCDSend(c->arg[0]); - break; + case CMD_LCD_RESET: { + LCDReset(); + break; + } + case CMD_LCD: { + LCDSend(packet->oldarg[0]); + break; + } #endif - case CMD_SETUP_WRITE: - case CMD_FINISH_WRITE: - case CMD_HARDWARE_RESET: - usb_disable(); + case CMD_SETUP_WRITE: + case CMD_FINISH_WRITE: + case CMD_HARDWARE_RESET: { + usb_disable(); - // (iceman) why this wait? - SpinDelay(1000); - AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; - // We're going to reset, and the bootrom will take control. - for(;;) {} - break; - - case CMD_START_FLASH: - if(common_area.flags.bootrom_present) { - common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE; - } - usb_disable(); - AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; - // We're going to flash, and the bootrom will take control. - for(;;) {} - break; - - 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(CMD_DEVICE_INFO,dev_info,0,0,0,0); - break; - } - default: - Dbprintf("%s: 0x%04x","unknown command:", c->cmd); - break; - } + // (iceman) why this wait? + SpinDelay(1000); + AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; + // We're going to reset, and the bootrom will take control. + for (;;) {} + break; + } + case CMD_START_FLASH: { + if (common_area.flags.bootrom_present) { + common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE; + } + usb_disable(); + AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; + // We're going to flash, and the bootrom will take control. + for (;;) {} + break; + } + 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; + } + reply_old(CMD_DEVICE_INFO, dev_info, 0, 0, 0, 0); + break; + } + default: { + Dbprintf("%s: 0x%04x", "unknown command:", packet->cmd); + break; + } + } } 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)); - common_area.magic = COMMON_AREA_MAGIC; - common_area.version = 1; - } - common_area.flags.osimage_present = 1; + SpinDelay(100); + clear_trace(); - LEDsoff(); - - usb_enable(); + if (common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) { + /* Initialize common area */ + memset(&common_area, 0, sizeof(common_area)); + common_area.magic = COMMON_AREA_MAGIC; + common_area.version = 1; + } + common_area.flags.osimage_present = 1; - // The FPGA gets its clock from us from PCK0 output, so set that up. - AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; - AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0; - 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_BASE_PIOA->PIO_OER = GPIO_PCK0; + LEDsoff(); - // Reset SPI - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // errata says it needs twice to be correctly set. - - // Reset SSC - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; + // The FPGA gets its clock from us from PCK0 output, so set that up. + AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; + AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0; + 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_BASE_PIOA->PIO_OER = GPIO_PCK0; + + // Reset SPI + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // errata says it needs twice to be correctly set. + + // Reset SSC + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; + + // Configure MUX + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Load the FPGA image, which we have stored in our flash. + // (the HF version by default) + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + StartTickCount(); - // Configure MUX - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Load the FPGA image, which we have stored in our flash. - // (the HF version by default) - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - StartTickCount(); - #ifdef WITH_LCD - LCDInit(); + LCDInit(); #endif #ifdef WITH_SMARTCARD - I2C_init(); + I2C_init(); #endif -#ifdef WITH_FPC - usart_init(); -#endif - uint8_t rx[sizeof(UsbCommand)]; - - for(;;) { - WDT_HIT(); - -#ifdef WITH_FPC - // check if there is a FPC USART1 message? - /* - uint32_t fpc_rxlen = usart_read(rx, sizeof(UsbCommand)); - if ( fpc_rxlen > 0) - Dbprintf("got a package [len %d] %02x", fpc_rxlen, rx[0]); - */ -#endif - - // Check if there is a usb packet available - if ( cmd_receive( (UsbCommand*)rx ) ) { - UsbPacketReceived(rx, sizeof(UsbCommand) ); - } - - // Press button for one second to enter a possible standalone mode - if (BUTTON_HELD(1000) > 0) { - -/* -* So this is the trigger to execute a standalone mod. Generic entrypoint by following the standalone/standalone.h headerfile -* All standalone mod "main loop" should be the RunMod() function. -* Since the standalone is either LF or HF, the somewhat bisarr defines below exists. -*/ -#if defined (WITH_LF) && ( defined (WITH_LF_SAMYRUN) || defined (WITH_LF_HIDBRUTE) || defined (WITH_LF_PROXBRUTE) ) - RunMod(); -#endif - -#if defined (WITH_ISO14443a) && ( defined (WITH_HF_YOUNG) || defined(WITH_HF_COLIN) || defined(WITH_HF_MATTYRUN) ) - RunMod(); +#ifdef WITH_FPC_USART + usart_init(USART_BAUD_RATE, USART_PARITY); #endif - } - } + // This is made as late as possible to ensure enumeration without timeout + // against device such as http://www.hobbytronics.co.uk/usb-host-board-v2 + usb_disable(); + usb_enable(); + +#ifdef WITH_FLASH + // If flash is not present, BUSY_TIMEOUT kicks in, let's do it after USB + loadT55xxConfig(); +#endif + + for (;;) { + WDT_HIT(); + + // Check if there is a packet available + PacketCommandNG rx; + memset(&rx.data, 0, sizeof(rx.data)); + + int ret = receive_ng(&rx); + if (ret == PM3_SUCCESS) { + PacketReceived(&rx); + } else if (ret != PM3_ENODATA) { + + Dbprintf("Error in frame reception: %d %s", ret, (ret == PM3_EIO) ? "PM3_EIO" : ""); + // TODO if error, shall we resync ? + } + + // Press button for one second to enter a possible standalone mode + button_status = BUTTON_HELD(1000); + if (button_status == BUTTON_HOLD) { + /* + * So this is the trigger to execute a standalone mod. Generic entrypoint by following the standalone/standalone.h headerfile + * All standalone mod "main loop" should be the RunMod() function. + */ + RunMod(); + } + } } diff --git a/armsrc/apps.h b/armsrc/apps.h index 7852d1439..41a1f0271 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -34,7 +34,6 @@ extern "C" { extern const uint8_t OddByteParity[256]; 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 @@ -46,8 +45,9 @@ void ReadMem(int addr); void __attribute__((noreturn)) AppMain(void); //void DbpIntegers(int a, int b, int c); void DbpString(char *str); +void DbpStringEx(uint32_t flags, char *str); void Dbprintf(const char *fmt, ...); -void DbprintfEx(uint32_t cmd, const char *fmt, ...); +void DbprintfEx(uint32_t flags, 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 @@ -59,15 +59,15 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci); uint16_t AvgAdc(int ch); void print_result(char *name, uint8_t *buf, size_t len); -void PrintToSendBuffer(void); +//void PrintToSendBuffer(void); void ToSendStuffBit(int b); void ToSendReset(void); -void ListenReaderField(int limit); +void ListenReaderField(uint8_t limit); extern int ToSendMax; extern uint8_t ToSend[]; -extern void StandAloneMode(void); -extern void printStandAloneModes(void); +void StandAloneMode(void); +void printStandAloneModes(void); /// lfops.h extern uint8_t decimation; @@ -81,14 +81,17 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); void AcquireTiType(void); void AcquireRawBitsTI(void); -void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycles); -void SimulateTagLowFrequency(int period, int gap, int ledcontrol); +void SimulateTagLowFrequencyEx(int period, int gap, bool ledcontrol, int numcycles); +void SimulateTagLowFrequency(int period, int gap, bool ledcontrol); void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); -void CmdHIDsimTAGEx(uint32_t hi, uint32_t lo, int ledcontrol, int numcycles); -void CmdHIDsimTAG(uint32_t hi, uint32_t 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 CmdHIDsimTAGEx(uint32_t hi, uint32_t lo, bool ledcontrol, int numcycles); +void CmdHIDsimTAG(uint32_t hi, uint32_t lo, bool ledcontrol); + +void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol); +void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); +void CmdPSKsimTag(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); + void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); // Realtime demodulation mode for AWID26 void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol); @@ -100,14 +103,22 @@ 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 T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode); -void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode); -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd); +void T55xxWriteBlock(uint8_t *data); +void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags); +void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd); void T55xxWakeUp(uint32_t Pwd); +void T55xx_ChkPwds(void); + void TurnReadLFOn(uint32_t delay); + void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); -void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd); +void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd); + void Cotag(uint32_t arg0); +void setT55xxConfig(uint8_t arg0, t55xx_config *c); +t55xx_config *getT55xxConfig(void); +void printT55xxConfig(void); +void loadT55xxConfig(void); /// iso14443b.h void SimulateIso14443bTag(uint32_t pupi); @@ -115,132 +126,123 @@ void AcquireRawAdcSamplesIso14443b(uint32_t parameter); void ReadSTMemoryIso14443b(uint8_t numofblocks); void RAMFUNC SniffIso14443b(void); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); -void SendRawCommand14443B_Ex(UsbCommand *c); +void SendRawCommand14443B_Ex(PacketCommandNG *c); void ClearFpgaShiftingRegisters(void); // iso14443a.h void RAMFUNC SniffIso14443a(uint8_t param); -void SimulateIso14443aTag(int tagType, int flags, uint8_t *data); -void ReaderIso14443a(UsbCommand *c); +void ReaderIso14443a(PacketCommandNG *c); // Also used in iclass.c //bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); -void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity); +void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); void iso14a_set_trigger(bool enable); // also used in emv -bool prepare_allocated_tag_modulation(tag_response_info_t * response_info); -int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len); +//bool prepare_allocated_tag_modulation(tag_response_info_t *response_info); +//int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len); // epa.h -void EPA_PACE_Collect_Nonce(UsbCommand * c); -void EPA_PACE_Replay(UsbCommand *c); +void EPA_PACE_Collect_Nonce(PacketCommandNG *c); +void EPA_PACE_Replay(PacketCommandNG *c); // mifarecmd.h -void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); +void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain); + void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -void MifareUC_Auth(uint8_t arg0, uint8_t *datain); +void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes); void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, 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 MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain); +void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); //void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); -void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); -void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareAcquireNonces(uint32_t arg0, uint32_t flags); +void MifareChkKeys(uint8_t *datain); void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -void MifareSetDbgLvl(uint16_t arg0); -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 MifareEMemClr(void); +void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain); +void MifareEMemGet(uint8_t blockno, uint8_t blockcnt); +int MifareECardLoad(uint32_t arg0, uint32_t arg1); + void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); void MifareCIdent(); // is "magic chinese" card? -void MifareSetMod(uint8_t mod, uint8_t *key); + +void MifareSetMod(uint8_t *datain); void MifareUSetPwd(uint8_t arg0, uint8_t *datain); void OnSuccessMagic(); void OnErrorMagic(uint8_t reason); int32_t dist_nt(uint32_t nt1, uint32_t nt2); -void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ); +void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype); //void RAMFUNC SniffMifare(uint8_t param); //desfire -void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); -void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); +void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain); +void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); // mifaredesfire.h bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); +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); +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); +size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout); void OnSuccess(); void OnError(uint8_t reason); // desfire_crypto.h -void *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings); -void *mifare_cryto_postprocess_data (desfiretag_t tag, void *data, size_t *nbytes, int communication_settings); -void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); -void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); -size_t key_block_size (const desfirekey_t key); -size_t padded_data_length (const size_t nbytes, const size_t block_size); -size_t maced_data_length (const desfirekey_t key, const size_t nbytes); -size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings); -void cmac_generate_subkeys (desfirekey_t key); -void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); +void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings); +void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings); +void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size); +void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation); +size_t key_block_size(const desfirekey_t key); +size_t padded_data_length(const size_t nbytes, const size_t block_size); +size_t maced_data_length(const desfirekey_t key, const size_t nbytes); +size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings); +void cmac_generate_subkeys(desfirekey_t key); +void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac); // iso15693.h void RecordRawAdcSamplesIso15693(void); void AcquireRawAdcSamplesIso15693(void); -void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg -void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg +void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg +void SimTagIso15693(uint32_t parameter, uint8_t *uid); // 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 DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI - atrox void Iso15693InitReader(void); // iclass.h void RAMFUNC SniffIClass(void); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void ReaderIClass(uint8_t arg0); -void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC); -void iClass_Authentication(uint8_t *MAC); +void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac); +void iClass_Authentication(uint8_t *mac); void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain); -void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); -void iClass_ReadBlk(uint8_t blockNo); -bool iClass_ReadBlock(uint8_t blockNo, uint8_t *data, uint8_t datalen); +void iClass_WriteBlock(uint8_t blockno, uint8_t *data); +void iClass_ReadBlk(uint8_t blockno); +bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len); void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); - -// hitag2.h -void SnoopHitag(uint32_t type); -void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); -void ReaderHitag(hitag_function htf, hitag_data* htd); -void WriterHitag(hitag_function htf, hitag_data* htd, int page); - -//hitagS.h -void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); -void ReadHitagS(hitag_function htf, hitag_data* htd); -void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); -void check_challenges(bool file_given, byte_t* data); +void iClass_ReadCheck(uint8_t blockno, uint8_t keytype); // cmd.h -bool cmd_receive(UsbCommand* cmd); -bool cmd_send(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void* data, size_t len); +int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); +int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); +int reply_ng(uint16_t cmd, int16_t status, uint8_t *data, size_t len); +int receive_ng(PacketCommandNG *rx); // util.h -void HfSnoop(int , int); +void HfSniff(int, int); //felica.c -extern void felica_sendraw(UsbCommand *c); -extern void felica_sniff(uint32_t samples, uint32_t triggers); -extern void felica_sim_lite(uint64_t uid); -extern void felica_dump_lite_s(); +void felica_sendraw(PacketCommandNG *c); +void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip); +void felica_sim_lite(uint64_t uid); +void felica_dump_lite_s(); #ifdef __cplusplus diff --git a/armsrc/buzzer.c b/armsrc/buzzer.c index 23e7e05d6..708b7d3f7 100644 --- a/armsrc/buzzer.c +++ b/armsrc/buzzer.c @@ -1,86 +1,86 @@ #include "buzzer.h" -void Ring_BEE_ONCE(uint16_t music_note) { +void Ring_BEE_ONCE(uint16_t music_note) { BEE_ON(); - SpinDelayUs(music_note); - BEE_OFF(); - SpinDelayUs(music_note); + SpinDelayUs(music_note); + BEE_OFF(); + SpinDelayUs(music_note); } void ring_2_7khz(uint16_t count) { - Ring_BEE_TIME(n_2_7khz,count); + Ring_BEE_TIME(n_2_7khz, count); } -void Ring_BEE_TIME(uint16_t music_note,uint16_t count) { - for(uint16_t i=0 ; i < count; i++) - Ring_BEE_ONCE(music_note); - SpinDelay(9); +void Ring_BEE_TIME(uint16_t music_note, uint16_t count) { + for (uint16_t i = 0 ; i < count; i++) + Ring_BEE_ONCE(music_note); + SpinDelay(9); } void Ring_ALL(uint16_t count) { - Ring_BEE_TIME(note_1, count); - Ring_BEE_TIME(note_2, count); - Ring_BEE_TIME(note_3, count); - Ring_BEE_TIME(note_4, count); - Ring_BEE_TIME(note_5, count); - Ring_BEE_TIME(note_6, count); - Ring_BEE_TIME(note_7, count); - SpinDelay(10); + Ring_BEE_TIME(note_1, count); + Ring_BEE_TIME(note_2, count); + Ring_BEE_TIME(note_3, count); + Ring_BEE_TIME(note_4, count); + Ring_BEE_TIME(note_5, count); + Ring_BEE_TIME(note_6, count); + Ring_BEE_TIME(note_7, count); + SpinDelay(10); } -void Ring_Little_Star(uint16_t count) { - Ring_BEE_TIME(note_1,count); - Ring_BEE_TIME(note_1,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_6,count); - Ring_BEE_TIME(note_6,count); - Ring_BEE_TIME(note_5,2*count); - LED_A_ON(); - /* - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_2,count); - Ring_BEE_TIME(note_2,count); - Ring_BEE_TIME(note_1,2*count); - LED_A_OFF(); +void Ring_Little_Star(uint16_t count) { + Ring_BEE_TIME(note_1, count); + Ring_BEE_TIME(note_1, count); + Ring_BEE_TIME(note_5, count); + Ring_BEE_TIME(note_5, count); + Ring_BEE_TIME(note_6, count); + Ring_BEE_TIME(note_6, count); + Ring_BEE_TIME(note_5, 2 * count); + LED_A_ON(); + /* + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_2,count); + Ring_BEE_TIME(note_2,count); + Ring_BEE_TIME(note_1,2*count); + LED_A_OFF(); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_2,2*count); - LED_A_ON(); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_2,2*count); + LED_A_ON(); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_2,2*count); - LED_A_OFF(); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_2,2*count); + LED_A_OFF(); - Ring_BEE_TIME(note_1,count); - Ring_BEE_TIME(note_1,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_5,count); - Ring_BEE_TIME(note_6,count); - Ring_BEE_TIME(note_6,count); - Ring_BEE_TIME(note_5,2*count); - LED_A_ON(); + Ring_BEE_TIME(note_1,count); + Ring_BEE_TIME(note_1,count); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_5,count); + Ring_BEE_TIME(note_6,count); + Ring_BEE_TIME(note_6,count); + Ring_BEE_TIME(note_5,2*count); + LED_A_ON(); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_4,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_3,count); - Ring_BEE_TIME(note_2,count); - Ring_BEE_TIME(note_2,count); - Ring_BEE_TIME(note_1,2*count); - LED_B_ON(); - */ -} \ No newline at end of file + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_4,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_3,count); + Ring_BEE_TIME(note_2,count); + Ring_BEE_TIME(note_2,count); + Ring_BEE_TIME(note_1,2*count); + LED_B_ON(); + */ +} diff --git a/armsrc/buzzer.h b/armsrc/buzzer.h index e253977cf..082450f04 100644 --- a/armsrc/buzzer.h +++ b/armsrc/buzzer.h @@ -20,11 +20,11 @@ #define note_7 506 #define note_8 0 -extern void Ring_BEE_ONCE(uint16_t music_note); -extern void Ring_BEE_TIME(uint16_t music_note,uint16_t count); -extern void ring_2_7khz(uint16_t count); -extern void Ring_ALL(uint16_t count); -extern void Ring_Little_Star(uint16_t count); +void Ring_BEE_ONCE(uint16_t music_note); +void Ring_BEE_TIME(uint16_t music_note, uint16_t count); +void ring_2_7khz(uint16_t count); +void Ring_ALL(uint16_t count); +void Ring_Little_Star(uint16_t count); #endif diff --git a/armsrc/des.c b/armsrc/des.c index 78ae87447..41b30734c 100644 --- a/armsrc/des.c +++ b/armsrc/des.c @@ -22,161 +22,161 @@ * \email daniel.otte@rub.de * \date 2007-06-16 * \brief DES and EDE-DES implementation - * \license GPLv3 or later - * + * \license GPLv3 or later + * */ #include "des.h" const uint8_t sbox[256] = { - /* S-box 1 */ - 0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07, - 0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38, - 0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50, - 0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D, - /* S-box 2 */ - 0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A, - 0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5, - 0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F, - 0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9, - /* S-box 3 */ - 0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28, - 0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1, - 0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7, - 0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C, - /* S-box 4 */ - 0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F, - 0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9, - 0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84, - 0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E, - /* S-box 5 */ - 0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9, - 0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86, - 0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E, - 0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53, - /* S-box 6 */ - 0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B, - 0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38, - 0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6, - 0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D, - /* S-box 7 */ - 0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61, - 0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86, - 0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92, - 0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C, - /* S-box 8 */ - 0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7, - 0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92, - 0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58, - 0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B + /* S-box 1 */ + 0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07, + 0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38, + 0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50, + 0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D, + /* S-box 2 */ + 0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A, + 0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5, + 0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F, + 0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9, + /* S-box 3 */ + 0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28, + 0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1, + 0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7, + 0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C, + /* S-box 4 */ + 0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F, + 0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9, + 0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84, + 0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E, + /* S-box 5 */ + 0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9, + 0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86, + 0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E, + 0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53, + /* S-box 6 */ + 0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B, + 0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38, + 0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6, + 0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D, + /* S-box 7 */ + 0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61, + 0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86, + 0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92, + 0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C, + /* S-box 8 */ + 0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7, + 0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92, + 0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58, + 0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B }; -const uint8_t e_permtab[] ={ - 4, 6, /* 4 bytes in 6 bytes out*/ - 32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1 +const uint8_t e_permtab[] = { + 4, 6, /* 4 bytes in 6 bytes out*/ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 }; -const uint8_t p_permtab[] ={ - 4, 4, /* 32 bit -> 32 bit */ - 16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25 +const uint8_t p_permtab[] = { + 4, 4, /* 32 bit -> 32 bit */ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 }; -const uint8_t ip_permtab[] ={ - 8, 8, /* 64 bit -> 64 bit */ - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7 +const uint8_t ip_permtab[] = { + 8, 8, /* 64 bit -> 64 bit */ + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 }; -const uint8_t inv_ip_permtab[] ={ - 8, 8, /* 64 bit -> 64 bit */ - 40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25 +const uint8_t inv_ip_permtab[] = { + 8, 8, /* 64 bit -> 64 bit */ + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 }; -const uint8_t pc1_permtab[] ={ - 8, 7, /* 64 bit -> 56 bit*/ - 57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36, - 63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4 +const uint8_t pc1_permtab[] = { + 8, 7, /* 64 bit -> 56 bit*/ + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 }; -const uint8_t pc2_permtab[] ={ - 7, 6, /* 56 bit -> 48 bit */ - 14, 17, 11, 24, 1, 5, - 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, - 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, - 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, - 46, 42, 50, 36, 29, 32 +const uint8_t pc2_permtab[] = { + 7, 6, /* 56 bit -> 48 bit */ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 }; const uint8_t splitin6bitword_permtab[] = { - 8, 8, /* 64 bit -> 64 bit */ - 64, 64, 1, 6, 2, 3, 4, 5, - 64, 64, 7, 12, 8, 9, 10, 11, - 64, 64, 13, 18, 14, 15, 16, 17, - 64, 64, 19, 24, 20, 21, 22, 23, - 64, 64, 25, 30, 26, 27, 28, 29, - 64, 64, 31, 36, 32, 33, 34, 35, - 64, 64, 37, 42, 38, 39, 40, 41, - 64, 64, 43, 48, 44, 45, 46, 47 + 8, 8, /* 64 bit -> 64 bit */ + 64, 64, 1, 6, 2, 3, 4, 5, + 64, 64, 7, 12, 8, 9, 10, 11, + 64, 64, 13, 18, 14, 15, 16, 17, + 64, 64, 19, 24, 20, 21, 22, 23, + 64, 64, 25, 30, 26, 27, 28, 29, + 64, 64, 31, 36, 32, 33, 34, 35, + 64, 64, 37, 42, 38, 39, 40, 41, + 64, 64, 43, 48, 44, 45, 46, 47 }; const uint8_t shiftkey_permtab[] = { - 7, 7, /* 56 bit -> 56 bit */ - 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 1, - 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 29 + 7, 7, /* 56 bit -> 56 bit */ + 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 1, + 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 29 }; const uint8_t shiftkeyinv_permtab[] = { - 7, 7, - 28, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, - 56, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55 + 7, 7, + 28, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, + 56, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55 }; /* @@ -198,247 +198,245 @@ const uint8_t shiftkeyinv_permtab[] = { 2 1 1 0 */ -#define ROTTABLE 0x7EFC +#define ROTTABLE 0x7EFC #define ROTTABLE_INV 0x3F7E /******************************************************************************/ -void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){ - uint8_t ob; /* in-bytes and out-bytes */ - uint8_t byte, bit; /* counter for bit and byte */ - ob = ptable[1]; - ptable = &(ptable[2]); - for(byte=0; byte>(x%8)) ){ - t|=0x01; - } - } - out[byte]=t; - } +void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out) { + uint8_t ob; /* in-bytes and out-bytes */ + uint8_t byte, bit; /* counter for bit and byte */ + ob = ptable[1]; + ptable = &(ptable[2]); + for (byte = 0; byte < ob; ++byte) { + uint8_t t = 0; + for (bit = 0; bit < 8; ++bit) { + uint8_t x = *ptable++ - 1; + t <<= 1; + if ((in[x / 8]) & (0x80 >> (x % 8))) { + t |= 0x01; + } + } + out[byte] = t; + } } /******************************************************************************/ -void changeendian32(uint32_t * a){ - *a = (*a & 0x000000FF) << 24 | - (*a & 0x0000FF00) << 8 | - (*a & 0x00FF0000) >> 8 | - (*a & 0xFF000000) >> 24; +void changeendian32(uint32_t *a) { + *a = (*a & 0x000000FF) << 24 | + (*a & 0x0000FF00) << 8 | + (*a & 0x00FF0000) >> 8 | + (*a & 0xFF000000) >> 24; } /******************************************************************************/ static inline -void shiftkey(uint8_t *key){ - uint8_t k[7]; - memcpy(k, key, 7); - permute((uint8_t*)shiftkey_permtab, k, key); +void shiftkey(uint8_t *key) { + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t *)shiftkey_permtab, k, key); } /******************************************************************************/ static inline -void shiftkey_inv(uint8_t *key){ - uint8_t k[7]; - memcpy(k, key, 7); - permute((uint8_t*)shiftkeyinv_permtab, k, key); - +void shiftkey_inv(uint8_t *key) { + uint8_t k[7]; + memcpy(k, key, 7); + permute((uint8_t *)shiftkeyinv_permtab, k, key); + } /******************************************************************************/ static inline -uint64_t splitin6bitwords(uint64_t a){ - uint64_t ret=0; - a &= 0x0000ffffffffffffLL; - permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret); - return ret; +uint64_t splitin6bitwords(uint64_t a) { + uint64_t ret = 0; + a &= 0x0000ffffffffffffLL; + permute((uint8_t *)splitin6bitword_permtab, (uint8_t *)&a, (uint8_t *)&ret); + return ret; } /******************************************************************************/ static inline -uint8_t substitute(uint8_t a, uint8_t * sbp){ - uint8_t x; - x = sbp[a>>1]; - x = (a&1)?x&0x0F:x>>4; - return x; - +uint8_t substitute(uint8_t a, uint8_t *sbp) { + uint8_t x; + x = sbp[a >> 1]; + x = (a & 1) ? x & 0x0F : x >> 4; + return x; + } /******************************************************************************/ -uint32_t des_f(uint32_t r, uint8_t* kr){ - uint8_t i; - uint32_t t=0,ret; - uint64_t data; - uint8_t *sbp; /* sboxpointer */ - permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data); - for(i=0; i<6; ++i) - ((uint8_t*)&data)[i] ^= kr[i]; - - /* Sbox substitution */ - data = splitin6bitwords(data); - sbp=(uint8_t*)sbox; - for(i=0; i<8; ++i){ - uint8_t x; - x = substitute(((uint8_t*)&data)[i], sbp); - t<<=4; - t |= x; - sbp += 32; - } - changeendian32(&t); - - permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret); +uint32_t des_f(uint32_t r, uint8_t *kr) { + uint8_t i; + uint32_t t = 0, ret; + uint64_t data; + uint8_t *sbp; /* sboxpointer */ + permute((uint8_t *)e_permtab, (uint8_t *)&r, (uint8_t *)&data); + for (i = 0; i < 6; ++i) + ((uint8_t *)&data)[i] ^= kr[i]; - return ret; + /* Sbox substitution */ + data = splitin6bitwords(data); + sbp = (uint8_t *)sbox; + for (i = 0; i < 8; ++i) { + uint8_t x; + x = substitute(((uint8_t *)&data)[i], sbp); + t <<= 4; + t |= x; + sbp += 32; + } + changeendian32(&t); + + permute((uint8_t *)p_permtab, (uint8_t *)&t, (uint8_t *)&ret); + + return ret; } /******************************************************************************/ typedef struct { - union { - uint8_t v8[8]; - uint32_t v32[2]; - } d; + union { + uint8_t v8[8]; + uint32_t v32[2]; + } d; } data_t; #define R (data.d.v32[1]) #define L (data.d.v32[0]) -void des_enc(void* out, const void* in, const void* key){ +void des_enc(void *out, const void *in, const void *key) { - uint8_t kr[6], k[7]; - uint8_t i; - data_t data; - - permute((uint8_t*)ip_permtab, (uint8_t*)in, data.d.v8); - permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); + uint8_t kr[6], k[7]; + uint8_t i; + data_t data; - for(i=0; i<8; ++i){ - shiftkey(k); - if(ROTTABLE&((1<<((i<<1)+0))) ) - shiftkey(k); - permute((uint8_t*)pc2_permtab, k, kr); - L ^= des_f(R, kr); - - shiftkey(k); - if(ROTTABLE&((1<<((i<<1)+1))) ) - shiftkey(k); - permute((uint8_t*)pc2_permtab, k, kr); - R ^= des_f(L, kr); + permute((uint8_t *)ip_permtab, (uint8_t *)in, data.d.v8); + permute((uint8_t *)pc1_permtab, (const uint8_t *)key, k); - } - /* L <-> R*/ - R ^= L; - L ^= R; - R ^= L; - - permute((uint8_t*)inv_ip_permtab, data.d.v8, (uint8_t*)out); + for (i = 0; i < 8; ++i) { + shiftkey(k); + if (ROTTABLE & ((1 << ((i << 1) + 0)))) + shiftkey(k); + permute((uint8_t *)pc2_permtab, k, kr); + L ^= des_f(R, kr); + + shiftkey(k); + if (ROTTABLE & ((1 << ((i << 1) + 1)))) + shiftkey(k); + permute((uint8_t *)pc2_permtab, k, kr); + R ^= des_f(L, kr); + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t *)inv_ip_permtab, data.d.v8, (uint8_t *)out); } /******************************************************************************/ -void des_dec(void* out, const void* in, const uint8_t* key){ +void des_dec(void *out, const void *in, const uint8_t *key) { - uint8_t kr[6],k[7]; - int8_t i; - data_t data; - - permute((uint8_t*)ip_permtab, (uint8_t*)in, data.d.v8); - permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k); - for(i=7; i>=0; --i){ - - permute((uint8_t*)pc2_permtab, k, kr); - L ^= des_f(R, kr); - shiftkey_inv(k); - if(ROTTABLE&((1<<((i<<1)+1))) ){ - shiftkey_inv(k); - } + uint8_t kr[6], k[7]; + int8_t i; + data_t data; - permute((uint8_t*)pc2_permtab, k, kr); - R ^= des_f(L, kr); - shiftkey_inv(k); - if(ROTTABLE&((1<<((i<<1)+0))) ){ - shiftkey_inv(k); - } + permute((uint8_t *)ip_permtab, (uint8_t *)in, data.d.v8); + permute((uint8_t *)pc1_permtab, (const uint8_t *)key, k); + for (i = 7; i >= 0; --i) { - } - /* L <-> R*/ - R ^= L; - L ^= R; - R ^= L; - - permute((uint8_t*)inv_ip_permtab, data.d.v8, (uint8_t*)out); + permute((uint8_t *)pc2_permtab, k, kr); + L ^= des_f(R, kr); + shiftkey_inv(k); + if (ROTTABLE & ((1 << ((i << 1) + 1)))) { + shiftkey_inv(k); + } + + permute((uint8_t *)pc2_permtab, k, kr); + R ^= des_f(L, kr); + shiftkey_inv(k); + if (ROTTABLE & ((1 << ((i << 1) + 0)))) { + shiftkey_inv(k); + } + + } + /* L <-> R*/ + R ^= L; + L ^= R; + R ^= L; + + permute((uint8_t *)inv_ip_permtab, data.d.v8, (uint8_t *)out); } /******************************************************************************/ -void tdes_enc(void* out, void* in, const void* key){ - des_enc(out, in, (uint8_t*)key + 0); - des_dec(out, out, (uint8_t*)key + 8); - des_enc(out, out, (uint8_t*)key +16); +void tdes_enc(void *out, void *in, const void *key) { + des_enc(out, in, (uint8_t *)key + 0); + des_dec(out, out, (uint8_t *)key + 8); + des_enc(out, out, (uint8_t *)key + 16); } /******************************************************************************/ -void tdes_dec(void* out, void* in, const uint8_t* key){ - des_dec(out, in, (uint8_t*)key +16); - des_enc(out, out, (uint8_t*)key + 8); - des_dec(out, out, (uint8_t*)key + 0); +void tdes_dec(void *out, void *in, const uint8_t *key) { + des_dec(out, in, (uint8_t *)key + 16); + des_enc(out, out, (uint8_t *)key + 8); + des_dec(out, out, (uint8_t *)key + 0); } - void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){ +void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { - if( length % 8 ) return; + if (length % 8) return; - uint8_t i; - uint8_t* tin = (uint8_t*) in; - uint8_t* tout = (uint8_t*) out; - - while( length > 0 ) - { - for( i = 0; i < 8; i++ ) - tout[i] = (unsigned char)( tin[i] ^ iv[i] ); - - des_enc(tout, tin, (uint8_t*)key + 0); - des_dec(tout, tout, (uint8_t*)key + 8); - des_enc(tout, tout, (uint8_t*)key + 0); - - memcpy( iv, tout, 8 ); - - tin += 8; - tout += 8; - length -= 8; - } - } - - void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){ - - if( length % 8 ) return; + uint8_t i; + uint8_t *tin = (uint8_t *) in; + uint8_t *tout = (uint8_t *) out; - uint8_t i; - unsigned char temp[8]; - uint8_t* tin = (uint8_t*) in; - uint8_t* tout = (uint8_t*) out; - - while( length > 0 ) - { - memcpy( temp, tin, 8 ); - - des_dec(tout, tin, (uint8_t*)key + 0); - des_enc(tout, tout, (uint8_t*)key + 8); - des_dec(tout, tout, (uint8_t*)key + 0); + while (length > 0) { + for (i = 0; i < 8; i++) + tout[i] = (unsigned char)(tin[i] ^ iv[i]); - for( i = 0; i < 8; i++ ) - tout[i] = (unsigned char)( tout[i] ^ iv[i] ); + des_enc(tout, tin, (uint8_t *)key + 0); + des_dec(tout, tout, (uint8_t *)key + 8); + des_enc(tout, tout, (uint8_t *)key + 0); - memcpy( iv, temp, 8 ); - - tin += 8; - tout += 8; - length -= 8; - } - } + memcpy(iv, tout, 8); + + tin += 8; + tout += 8; + length -= 8; + } +} + +void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) { + + if (length % 8) return; + + uint8_t i; + unsigned char temp[8]; + uint8_t *tin = (uint8_t *) in; + uint8_t *tout = (uint8_t *) out; + + while (length > 0) { + memcpy(temp, tin, 8); + + des_dec(tout, tin, (uint8_t *)key + 0); + des_enc(tout, tout, (uint8_t *)key + 8); + des_dec(tout, tout, (uint8_t *)key + 0); + + for (i = 0; i < 8; i++) + tout[i] = (unsigned char)(tout[i] ^ iv[i]); + + memcpy(iv, temp, 8); + + tin += 8; + tout += 8; + length -= 8; + } +} /******************************************************************************/ diff --git a/armsrc/des.h b/armsrc/des.h index 03b9f6469..0d2cceefb 100644 --- a/armsrc/des.h +++ b/armsrc/des.h @@ -17,12 +17,12 @@ along with this program. If not, see . */ /** - * \file des.h - * \author Daniel Otte - * \date 2007-06-16 - * \brief des and tdes declarations - * \license GPLv3 or later - * + * \file des.h + * \author Daniel Otte + * \date 2007-06-16 + * \brief des and tdes declarations + * \license GPLv3 or later + * */ #ifndef __DES_H_ #define __DES_H_ @@ -46,65 +46,65 @@ /** \fn void des_enc(void* out, const void* in, const void* key) * \brief encrypt a block with DES - * + * * This function encrypts a block of 64 bits (8 bytes) with the DES algorithm. * Key expansion is done automatically. The key is 64 bits long, but note that * only 56 bits are used (the LSB of each byte is dropped). The input and output * blocks may overlap. - * + * * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from * \param key pointer to the key (64 bit = 8 byte) */ -void des_enc(void* out, const void* in, const void* key); +void des_enc(void *out, const void *in, const void *key); /** \fn void des_dec(void* out, const void* in, const void* key) * \brief decrypt a block with DES - * + * * This function decrypts a block of 64 bits (8 bytes) with the DES algorithm. * Key expansion is done automatically. The key is 64 bits long, but note that * only 56 bits are used (the LSB of each byte is dropped). The input and output * blocks may overlap. - * + * * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from * \param key pointer to the key (64 bit = 8 byte) */ //void des_dec(void* out, const void* in, const void* key); -void des_dec(void* out, const void* in, const uint8_t* key); +void des_dec(void *out, const void *in, const uint8_t *key); /** \fn void tdes_enc(void* out, const void* in, const void* key) * \brief encrypt a block with Tripple-DES - * + * * This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) * algorithm. Key expansion is done automatically. The key is 192 bits long, but * note that only 178 bits are used (the LSB of each byte is dropped). The input * and output blocks may overlap. - * + * * \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to * \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from * \param key pointer to the key (192 bit = 24 byte) */ //void tdes_enc(void* out, const void* in, const void* key); -void tdes_enc(void* out, void* in, const void* key); +void tdes_enc(void *out, void *in, const void *key); /** \fn void tdes_dec(void* out, const void* in, const void* key) * \brief decrypt a block with Tripple-DES - * + * * This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE) * algorithm. Key expansion is done automatically. The key is 192 bits long, but * note that only 178 bits are used (the LSB of each byte is dropped). The input * and output blocks may overlap. - * + * * \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to * \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from * \param key pointer to the key (192 bit = 24 byte) */ - //void tdes_dec(void* out, const void* in, const void* key); - void tdes_dec(void* out, void* in, const uint8_t* key); - - void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]); - void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]); +//void tdes_dec(void* out, const void* in, const void* key); +void tdes_dec(void *out, void *in, const uint8_t *key); + +void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); +void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]); // Copied from des.h in desfire imp. typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */ diff --git a/armsrc/desfire_crypto.c b/armsrc/desfire_crypto.c index 5cb36054c..10ddf4162 100644 --- a/armsrc/desfire_crypto.c +++ b/armsrc/desfire_crypto.c @@ -1,11 +1,11 @@ /*- * Copyright (C) 2010, Romain Tartiere. - * + * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 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 @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see - * + * * $Id$ */ @@ -27,78 +27,80 @@ */ #include "desfire_crypto.h" -static void xor (const uint8_t *ivect, uint8_t *data, const size_t len); -static size_t key_macing_length (desfirekey_t key); +static void xor(const uint8_t *ivect, uint8_t *data, const size_t len); +static size_t key_macing_length(desfirekey_t key); // iceman, see memxor inside string.c, dest/src swapped.. -static void xor (const uint8_t *ivect, uint8_t *data, const size_t len) { +static void xor(const uint8_t *ivect, uint8_t *data, const size_t len) { for (size_t i = 0; i < len; i++) { data[i] ^= ivect[i]; } } -void cmac_generate_subkeys ( desfirekey_t key) { - int kbs = key_block_size (key); +void cmac_generate_subkeys(desfirekey_t key) { + int kbs = key_block_size(key); const uint8_t R = (kbs == 8) ? 0x1B : 0x87; uint8_t l[kbs]; - memset (l, 0, kbs); + memset(l, 0, kbs); uint8_t ivect[kbs]; - memset (ivect, 0, kbs); + memset(ivect, 0, kbs); - mifare_cypher_blocks_chained (NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER); + mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER); bool xor = false; // Used to compute CMAC on complete blocks - memcpy (key->cmac_sk1, l, kbs); + memcpy(key->cmac_sk1, l, kbs); xor = l[0] & 0x80; - lsl (key->cmac_sk1, kbs); + lsl(key->cmac_sk1, kbs); if (xor) - key->cmac_sk1[kbs-1] ^= R; + key->cmac_sk1[kbs - 1] ^= R; // Used to compute CMAC on the last block if non-complete - memcpy (key->cmac_sk2, key->cmac_sk1, kbs); + memcpy(key->cmac_sk2, key->cmac_sk1, kbs); xor = key->cmac_sk1[0] & 0x80; - lsl (key->cmac_sk2, kbs); + lsl(key->cmac_sk2, kbs); if (xor) - key->cmac_sk2[kbs-1] ^= R; + key->cmac_sk2[kbs - 1] ^= R; } -void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) { - int kbs = key_block_size (key); - uint8_t *buffer = malloc (padded_data_length (len, kbs)); +void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac) { + int kbs = key_block_size(key); + uint8_t *buffer = malloc(padded_data_length(len, kbs)); - memcpy (buffer, data, len); + memcpy(buffer, data, len); if ((!len) || (len % kbs)) { buffer[len++] = 0x80; while (len % kbs) { buffer[len++] = 0x00; } - xor (key->cmac_sk2, buffer + len - kbs, kbs); + xor(key->cmac_sk2, buffer + len - kbs, kbs); } else { - xor (key->cmac_sk1, buffer + len - kbs, kbs); + xor(key->cmac_sk1, buffer + len - kbs, kbs); } - mifare_cypher_blocks_chained (NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER); + mifare_cypher_blocks_chained(NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER); - memcpy (cmac, ivect, kbs); - free(buffer); + memcpy(cmac, ivect, kbs); + free(buffer); } -size_t key_block_size (const desfirekey_t key) { +size_t key_block_size(const desfirekey_t key) { + if (key == NULL) + return 0; size_t block_size = 8; switch (key->type) { - case T_DES: - case T_3DES: - case T_3K3DES: - block_size = 8; - break; - case T_AES: - block_size = 16; - break; + case T_DES: + case T_3DES: + case T_3K3DES: + block_size = 8; + break; + case T_AES: + block_size = 16; + break; } return block_size; } @@ -106,17 +108,17 @@ size_t key_block_size (const desfirekey_t key) { /* * Size of MACing produced with the key. */ -static size_t key_macing_length (const desfirekey_t key) { +static size_t key_macing_length(const desfirekey_t key) { size_t mac_length = MAC_LENGTH; switch (key->type) { - case T_DES: - case T_3DES: - mac_length = MAC_LENGTH; - break; - case T_3K3DES: - case T_AES: - mac_length = CMAC_LENGTH; - break; + case T_DES: + case T_3DES: + mac_length = MAC_LENGTH; + break; + case T_3K3DES: + case T_AES: + mac_length = CMAC_LENGTH; + break; } return mac_length; } @@ -124,7 +126,7 @@ static size_t key_macing_length (const desfirekey_t key) { /* * Size required to store nbytes of data in a buffer of size n*block_size. */ -size_t padded_data_length (const size_t nbytes, const size_t block_size) { +size_t padded_data_length(const size_t nbytes, const size_t block_size) { if ((!nbytes) || (nbytes % block_size)) return ((nbytes / block_size) + 1) * block_size; else @@ -134,31 +136,31 @@ size_t padded_data_length (const size_t nbytes, const size_t block_size) { /* * Buffer size required to MAC nbytes of data */ -size_t maced_data_length (const desfirekey_t key, const size_t nbytes) { - return nbytes + key_macing_length (key); +size_t maced_data_length(const desfirekey_t key, const size_t nbytes) { + return nbytes + key_macing_length(key); } /* * Buffer size required to encipher nbytes of data and a two bytes CRC. */ -size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings) { +size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings) { size_t crc_length = 0; if (!(communication_settings & NO_CRC)) { switch (DESFIRE(tag)->authentication_scheme) { - case AS_LEGACY: - crc_length = 2; - break; - case AS_NEW: - crc_length = 4; - break; + case AS_LEGACY: + crc_length = 2; + break; + case AS_NEW: + crc_length = 4; + break; } } - size_t block_size = DESFIRE(tag)->session_key ? key_block_size (DESFIRE(tag)->session_key) : 1; + size_t block_size = DESFIRE(tag)->session_key ? key_block_size(DESFIRE(tag)->session_key) : 1; - return padded_data_length (nbytes + crc_length, block_size); + return padded_data_length(nbytes + crc_length, block_size); } -void* mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings) { +void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings) { uint8_t *res = data; uint8_t mac[4]; size_t edl; @@ -169,127 +171,125 @@ void* mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes return data; switch (communication_settings & MDCM_MASK) { - case MDCM_PLAIN: - if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) - break; + case MDCM_PLAIN: + if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) + break; - /* - * When using new authentication methods, PLAIN data transmission from - * the PICC to the PCD are CMACed, so we have to maintain the - * cryptographic initialisation vector up-to-date to check data - * integrity later. - * - * The only difference with CMACed data transmission is that the CMAC - * is not apended to the data send by the PCD to the PICC. - */ + /* + * When using new authentication methods, PLAIN data transmission from + * the PICC to the PCD are CMACed, so we have to maintain the + * cryptographic initialisation vector up-to-date to check data + * integrity later. + * + * The only difference with CMACed data transmission is that the CMAC + * is not apended to the data send by the PCD to the PICC. + */ - append_mac = false; + append_mac = false; /* pass through */ - case MDCM_MACED: - switch (DESFIRE(tag)->authentication_scheme) { - case AS_LEGACY: - if (!(communication_settings & MAC_COMMAND)) - break; + case MDCM_MACED: + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + if (!(communication_settings & MAC_COMMAND)) + break; - /* pass through */ - edl = padded_data_length (*nbytes - offset, key_block_size (DESFIRE(tag)->session_key)) + offset; + /* pass through */ + edl = padded_data_length(*nbytes - offset, key_block_size(DESFIRE(tag)->session_key)) + offset; - // Fill in the crypto buffer with data ... - memcpy (res, data, *nbytes); - // ... and 0 padding - memset (res + *nbytes, 0, edl - *nbytes); + // Fill in the crypto buffer with data ... + memcpy(res, data, *nbytes); + // ... and 0 padding + memset(res + *nbytes, 0, edl - *nbytes); - mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, edl - offset, MCD_SEND, MCO_ENCYPHER); + mifare_cypher_blocks_chained(tag, NULL, NULL, res + offset, edl - offset, MCD_SEND, MCO_ENCYPHER); - memcpy (mac, res + edl - 8, 4); + memcpy(mac, res + edl - 8, 4); - // Copy again provided data (was overwritten by mifare_cypher_blocks_chained) - memcpy (res, data, *nbytes); + // Copy again provided data (was overwritten by mifare_cypher_blocks_chained) + memcpy(res, data, *nbytes); - if (!(communication_settings & MAC_COMMAND)) - break; - // Append MAC - size_t bla = maced_data_length (DESFIRE(tag)->session_key, *nbytes - offset) + offset; - bla++; + if (!(communication_settings & MAC_COMMAND)) + break; + // Append MAC + size_t bla = maced_data_length(DESFIRE(tag)->session_key, *nbytes - offset) + offset; + bla++; - memcpy (res + *nbytes, mac, 4); + memcpy(res + *nbytes, mac, 4); - *nbytes += 4; - break; - case AS_NEW: - if (!(communication_settings & CMAC_COMMAND)) - break; - cmac (key, DESFIRE (tag)->ivect, res, *nbytes, DESFIRE (tag)->cmac); + *nbytes += 4; + break; + case AS_NEW: + if (!(communication_settings & CMAC_COMMAND)) + break; + cmac(key, DESFIRE(tag)->ivect, res, *nbytes, DESFIRE(tag)->cmac); - if (append_mac) { - size_t len = maced_data_length (key, *nbytes); - ++len; - memcpy (res, data, *nbytes); - memcpy (res + *nbytes, DESFIRE (tag)->cmac, CMAC_LENGTH); - *nbytes += CMAC_LENGTH; + if (append_mac) { + size_t len = maced_data_length(key, *nbytes); + ++len; + memcpy(res, data, *nbytes); + memcpy(res + *nbytes, DESFIRE(tag)->cmac, CMAC_LENGTH); + *nbytes += CMAC_LENGTH; + } + break; } - break; - } - break; - case MDCM_ENCIPHERED: - /* |<-------------- data -------------->| - * |<--- offset -->| | - * +---------------+--------------------+-----+---------+ - * | CMD + HEADERS | DATA TO BE SECURED | CRC | PADDING | - * +---------------+--------------------+-----+---------+ ---------------- - * | |<~~~~v~~~~~~~~~~~~~>| ^ | | (DES / 3DES) - * | | `---- crc16() ----' | | - * | | | ^ | | ----- *or* ----- - * |<~~~~~~~~~~~~~~~~~~~~v~~~~~~~~~~~~~>| ^ | | (3K3DES / AES) - * | `---- crc32() ----' | | - * | | ---- *then* ---- - * |<---------------------------------->| - * encypher()/decypher() - */ + break; + case MDCM_ENCIPHERED: + /* |<-------------- data -------------->| + * |<--- offset -->| | + * +---------------+--------------------+-----+---------+ + * | CMD + HEADERS | DATA TO BE SECURED | CRC | PADDING | + * +---------------+--------------------+-----+---------+ ---------------- + * | |<~~~~v~~~~~~~~~~~~~>| ^ | | (DES / 3DES) + * | | `---- crc16() ----' | | + * | | | ^ | | ----- *or* ----- + * |<~~~~~~~~~~~~~~~~~~~~v~~~~~~~~~~~~~>| ^ | | (3K3DES / AES) + * | `---- crc32() ----' | | + * | | ---- *then* ---- + * |<---------------------------------->| + * encypher()/decypher() + */ if (!(communication_settings & ENC_COMMAND)) break; - edl = enciphered_data_length (tag, *nbytes - offset, communication_settings) + offset; + edl = enciphered_data_length(tag, *nbytes - offset, communication_settings) + offset; // Fill in the crypto buffer with data ... - memcpy (res, data, *nbytes); + memcpy(res, data, *nbytes); if (!(communication_settings & NO_CRC)) { // ... CRC ... - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - AddCrc14A(res + offset, *nbytes - offset); - *nbytes += 2; - break; - case AS_NEW: - crc32_append (res, *nbytes); - *nbytes += 4; - break; + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + AddCrc14A(res + offset, *nbytes - offset); + *nbytes += 2; + break; + case AS_NEW: + crc32_append(res, *nbytes); + *nbytes += 4; + break; } } // ... and padding - memset (res + *nbytes, 0, edl - *nbytes); + memset(res + *nbytes, 0, edl - *nbytes); *nbytes = edl; - mifare_cypher_blocks_chained (tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER); - break; - default: + mifare_cypher_blocks_chained(tag, NULL, NULL, res + offset, *nbytes - offset, MCD_SEND, (AS_NEW == DESFIRE(tag)->authentication_scheme) ? MCO_ENCYPHER : MCO_DECYPHER); + break; + default: - *nbytes = -1; - res = NULL; - break; + *nbytes = -1; + res = NULL; + break; } return res; } -void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) -{ +void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) { void *res = data; - size_t edl; void *edata = NULL; uint8_t first_cmac_byte = 0x00; @@ -303,300 +303,296 @@ void* mifare_cryto_postprocess_data (desfiretag_t tag, void *data, size_t *nbyte return res; switch (communication_settings & MDCM_MASK) { - case MDCM_PLAIN: + case MDCM_PLAIN: - if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) - break; + if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) + break; /* pass through */ - case MDCM_MACED: - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - if (communication_settings & MAC_VERIFY) { - *nbytes -= key_macing_length (key); - if (*nbytes <= 0) { - *nbytes = -1; - res = NULL; + case MDCM_MACED: + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + if (communication_settings & MAC_VERIFY) { + *nbytes -= key_macing_length(key); + if (*nbytes == 0) { + *nbytes = -1; + res = NULL; #ifdef WITH_DEBUG - Dbprintf ("No room for MAC!"); + Dbprintf("No room for MAC!"); #endif + break; + } + + size_t edl = enciphered_data_length(tag, *nbytes - 1, communication_settings); + edata = malloc(edl); + + memcpy(edata, data, *nbytes - 1); + memset((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1); + + mifare_cypher_blocks_chained(tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER); + + if (0 != memcmp((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) { +#ifdef WITH_DEBUG + Dbprintf("MACing not verified"); + hexdump((uint8_t *)data + *nbytes - 1, key_macing_length(key), "Expect ", 0); + hexdump((uint8_t *)edata + edl - 8, key_macing_length(key), "Actual ", 0); +#endif + DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } + } break; - } + case AS_NEW: + if (!(communication_settings & CMAC_COMMAND)) + break; + if (communication_settings & CMAC_VERIFY) { + if (*nbytes < 9) { + *nbytes = -1; + res = NULL; + break; + } + first_cmac_byte = ((uint8_t *)data)[*nbytes - 9]; + ((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes - 1]; + } - edl = enciphered_data_length (tag, *nbytes - 1, communication_settings); - edata = malloc (edl); + int n = (communication_settings & CMAC_VERIFY) ? 8 : 0; + cmac(key, DESFIRE(tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE(tag)->cmac); - memcpy (edata, data, *nbytes - 1); - memset ((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1); - - mifare_cypher_blocks_chained (tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER); - - if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) { + if (communication_settings & CMAC_VERIFY) { + ((uint8_t *)data)[*nbytes - 9] = first_cmac_byte; + if (0 != memcmp(DESFIRE(tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) { #ifdef WITH_DEBUG - Dbprintf ("MACing not verified"); - hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0); - hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0); + Dbprintf("CMAC NOT verified :-("); + hexdump((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); + hexdump(DESFIRE(tag)->cmac, 8, "Actual ", 0); #endif - DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; - *nbytes = -1; - res = NULL; - } + DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } else { + *nbytes -= 8; + } + } + break; } + + free(edata); + break; - case AS_NEW: - if (!(communication_settings & CMAC_COMMAND)) - break; - if (communication_settings & CMAC_VERIFY) { - if (*nbytes < 9) { - *nbytes = -1; - res = NULL; + case MDCM_ENCIPHERED: + (*nbytes)--; + bool verified = false; + int crc_pos = 0x00; + int end_crc_pos = 0x00; + uint8_t x; + + /* + * AS_LEGACY: + * ,-----------------+-------------------------------+--------+ + * \ BLOCK n-1 | BLOCK n | STATUS | + * / PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 | + * `-----------------+-------------------------------+--------+ + * + * <------------ DATA ------------> + * FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING + * + * AS_NEW: + * ,-------------------------------+-----------------------------------------------+--------+ + * \ BLOCK n-1 | BLOCK n | STATUS | + * / PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 | + * `-------------------------------+-----------------------------------------------+--------+ + * <----------------------------------- DATA ------------------------------------->| + * + * <----------------- DATA ----------------> + * FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS + * `------------------' + */ + + mifare_cypher_blocks_chained(tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER); + + /* + * Look for the CRC and ensure it is followed by NULL padding. We + * can't start by the end because the CRC is supposed to be 0 when + * verified, and accumulating 0's in it should not change it. + */ + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks + if (crc_pos < 0) { + /* Single block */ + crc_pos = 0; + } + break; + case AS_NEW: + /* Move status between payload and CRC */ + res = DESFIRE(tag)->crypto_buffer; + memcpy(res, data, *nbytes); + + crc_pos = (*nbytes) - 16 - 3; + if (crc_pos < 0) { + /* Single block */ + crc_pos = 0; + } + memcpy((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos); + ((uint8_t *)res)[crc_pos] = 0x00; + crc_pos++; + *nbytes += 1; break; - } - first_cmac_byte = ((uint8_t *)data)[*nbytes - 9]; - ((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes-1]; } - int n = (communication_settings & CMAC_VERIFY) ? 8 : 0; - cmac (key, DESFIRE (tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE (tag)->cmac); + do { + uint16_t crc_16 = 0x00; + uint32_t crc; + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + AddCrc14A((uint8_t *)res, end_crc_pos); + end_crc_pos = crc_pos + 2; + // - if (communication_settings & CMAC_VERIFY) { - ((uint8_t *)data)[*nbytes - 9] = first_cmac_byte; - if (0 != memcmp (DESFIRE (tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) { -#ifdef WITH_DEBUG - Dbprintf ("CMAC NOT verified :-("); - hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); - hexdump (DESFIRE (tag)->cmac, 8, "Actual ", 0); -#endif - DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; - *nbytes = -1; - res = NULL; + + crc = crc_16; + break; + case AS_NEW: + end_crc_pos = crc_pos + 4; + crc32_ex(res, end_crc_pos, (uint8_t *)&crc); + break; + } + if (!crc) { + verified = true; + for (int n = end_crc_pos; n < *nbytes - 1; n++) { + uint8_t byte = ((uint8_t *)res)[n]; + if (!((0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)))) + verified = false; + } + } + if (verified) { + *nbytes = crc_pos; + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + ((uint8_t *)data)[(*nbytes)++] = 0x00; + break; + case AS_NEW: + /* The status byte was already before the CRC */ + break; + } } else { - *nbytes -= 8; + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + break; + case AS_NEW: + x = ((uint8_t *)res)[crc_pos - 1]; + ((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos]; + ((uint8_t *)res)[crc_pos] = x; + break; + } + crc_pos++; } - } - break; - } + } while (!verified && (end_crc_pos < *nbytes)); - free (edata); - - break; - case MDCM_ENCIPHERED: - (*nbytes)--; - bool verified = false; - int crc_pos = 0x00; - int end_crc_pos = 0x00; - uint8_t x; - - /* - * AS_LEGACY: - * ,-----------------+-------------------------------+--------+ - * \ BLOCK n-1 | BLOCK n | STATUS | - * / PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 | - * `-----------------+-------------------------------+--------+ - * - * <------------ DATA ------------> - * FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING - * - * AS_NEW: - * ,-------------------------------+-----------------------------------------------+--------+ - * \ BLOCK n-1 | BLOCK n | STATUS | - * / PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 | - * `-------------------------------+-----------------------------------------------+--------+ - * <----------------------------------- DATA ------------------------------------->| - * - * <----------------- DATA ----------------> - * FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS - * `------------------' - */ - - mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER); - - /* - * Look for the CRC and ensure it is followed by NULL padding. We - * can't start by the end because the CRC is supposed to be 0 when - * verified, and accumulating 0's in it should not change it. - */ - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks - if (crc_pos < 0) { - /* Single block */ - crc_pos = 0; - } - break; - case AS_NEW: - /* Move status between payload and CRC */ - res = DESFIRE (tag)->crypto_buffer; - memcpy (res, data, *nbytes); - - crc_pos = (*nbytes) - 16 - 3; - if (crc_pos < 0) { - /* Single block */ - crc_pos = 0; - } - memcpy ((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos); - ((uint8_t *)res)[crc_pos] = 0x00; - crc_pos++; - *nbytes += 1; - break; - } - - do { - uint16_t crc16 =0x00; - uint32_t crc; - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - AddCrc14A( (uint8_t*)res, end_crc_pos); - end_crc_pos = crc_pos + 2; - // - - - crc = crc16; - break; - case AS_NEW: - end_crc_pos = crc_pos + 4; - crc32_ex (res, end_crc_pos, (uint8_t *)&crc); - break; - } - if (!crc) { - verified = true; - for (int n = end_crc_pos; n < *nbytes - 1; n++) { - uint8_t byte = ((uint8_t *)res)[n]; - if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) )) - verified = false; - } - } - if (verified) { - *nbytes = crc_pos; - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - ((uint8_t *)data)[(*nbytes)++] = 0x00; - break; - case AS_NEW: - /* The status byte was already before the CRC */ - break; - } - } else { - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - break; - case AS_NEW: - x = ((uint8_t *)res)[crc_pos - 1]; - ((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos]; - ((uint8_t *)res)[crc_pos] = x; - break; - } - crc_pos++; - } - } while (!verified && (end_crc_pos < *nbytes)); - - if (!verified) { + if (!verified) { #ifdef WITH_DEBUG - /* FIXME In some configurations, the file is transmitted PLAIN */ - Dbprintf("CRC not verified in decyphered stream"); + /* FIXME In some configurations, the file is transmitted PLAIN */ + Dbprintf("CRC not verified in decyphered stream"); #endif - DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; + DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR; + *nbytes = -1; + res = NULL; + } + + break; + default: + Dbprintf("Unknown communication settings"); *nbytes = -1; res = NULL; - } - - break; - default: - Dbprintf("Unknown communication settings"); - *nbytes = -1; - res = NULL; - break; + break; } return res; } -void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size) -{ +void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size) { uint8_t ovect[MAX_CRYPTO_BLOCK_SIZE]; if (direction == MCD_SEND) { - xor (ivect, data, block_size); + xor(ivect, data, block_size); } else { - memcpy (ovect, data, block_size); + memcpy(ovect, data, block_size); } uint8_t edata[MAX_CRYPTO_BLOCK_SIZE]; switch (key->type) { - case T_DES: - switch (operation) { - case MCO_ENCYPHER: - //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); - des_enc(edata, data, key->data); + case T_DES: + switch (operation) { + case MCO_ENCYPHER: + //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + des_enc(edata, data, key->data); + break; + case MCO_DECYPHER: + //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + des_dec(edata, data, key->data); + break; + } break; - case MCO_DECYPHER: - //DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); - des_dec(edata, data, key->data); + case T_3DES: + switch (operation) { + case MCO_ENCYPHER: + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + tdes_enc(edata, data, key->data); + break; + case MCO_DECYPHER: + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + tdes_dec(data, edata, key->data); + break; + } break; - } - break; - case T_3DES: - switch (operation) { - case MCO_ENCYPHER: - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); - // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); - tdes_enc(edata,data, key->data); + case T_3K3DES: + switch (operation) { + case MCO_ENCYPHER: + tdes_enc(edata, data, key->data); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT); + break; + case MCO_DECYPHER: + tdes_dec(data, edata, key->data); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT); + // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); + // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); + break; + } break; - case MCO_DECYPHER: - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); - // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); - tdes_dec(data, edata, key->data); + case T_AES: + switch (operation) { + case MCO_ENCYPHER: { + AesCtx ctx; + AesCtxIni(&ctx, ivect, key->data, KEY128, CBC); + AesEncrypt(&ctx, data, edata, sizeof(edata)); + break; + } + case MCO_DECYPHER: { + AesCtx ctx; + AesCtxIni(&ctx, ivect, key->data, KEY128, CBC); + AesDecrypt(&ctx, edata, data, sizeof(edata)); + break; + } + } break; - } - break; - case T_3K3DES: - switch (operation) { - case MCO_ENCYPHER: - tdes_enc(edata,data, key->data); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT); - // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_ENCRYPT); - break; - case MCO_DECYPHER: - tdes_dec(data, edata, key->data); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), DES_DECRYPT); - // DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT); - // DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT); - break; - } - break; - case T_AES: - switch (operation) - { - case MCO_ENCYPHER: - { - AesCtx ctx; - AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); - AesEncrypt(&ctx, data, edata, sizeof(edata) ); - break; - } - case MCO_DECYPHER: - { - AesCtx ctx; - AesCtxIni(&ctx, ivect, key->data, KEY128,CBC); - AesDecrypt(&ctx, edata, data, sizeof(edata)); - break; - } - } - break; } - memcpy (data, edata, block_size); + memcpy(data, edata, block_size); if (direction == MCD_SEND) { - memcpy (ivect, data, block_size); + memcpy(ivect, data, block_size); } else { - xor (ivect, data, block_size); - memcpy (ivect, ovect, block_size); + xor(ivect, data, block_size); + memcpy(ivect, ovect, block_size); } } @@ -610,29 +606,29 @@ void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect * Because the tag may contain additional data, one may need to call this * function with tag, key and ivect defined. */ -void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation) { +void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation) { size_t block_size; if (tag) { if (!key) - key = DESFIRE (tag)->session_key; + key = DESFIRE(tag)->session_key; if (!ivect) - ivect = DESFIRE (tag)->ivect; + ivect = DESFIRE(tag)->ivect; - switch (DESFIRE (tag)->authentication_scheme) { - case AS_LEGACY: - memset (ivect, 0, MAX_CRYPTO_BLOCK_SIZE); - break; - case AS_NEW: - break; + switch (DESFIRE(tag)->authentication_scheme) { + case AS_LEGACY: + memset(ivect, 0, MAX_CRYPTO_BLOCK_SIZE); + break; + case AS_NEW: + break; } } - block_size = key_block_size (key); + block_size = key_block_size(key); size_t offset = 0; while (offset < data_size) { - mifare_cypher_single_block (key, data + offset, ivect, direction, operation, block_size); + mifare_cypher_single_block(key, data + offset, ivect, direction, operation, block_size); offset += block_size; } -} \ No newline at end of file +} diff --git a/armsrc/desfire_key.c b/armsrc/desfire_key.c index 800ff6da6..e1f880c8b 100644 --- a/armsrc/desfire_key.c +++ b/armsrc/desfire_key.c @@ -1,11 +1,11 @@ /*- * Copyright (C) 2010, Romain Tartiere. - * + * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 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 @@ -13,88 +13,88 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see - * + * * $Id$ */ #include "desfire_key.h" -static inline void update_key_schedules (desfirekey_t key); +static inline void update_key_schedules(desfirekey_t key); -static inline void update_key_schedules (desfirekey_t key) { +static inline void update_key_schedules(desfirekey_t key) { // DES_set_key ((DES_cblock *)key->data, &(key->ks1)); // DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2)); // if (T_3K3DES == key->type) { - // DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3)); + // DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3)); // } } -void Desfire_des_key_new (const uint8_t value[8], desfirekey_t key) { +void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key) { uint8_t data[8]; - memcpy (data, value, 8); - for (int n=0; n < 8; n++) + memcpy(data, value, 8); + for (int n = 0; n < 8; n++) data[n] &= 0xfe; - Desfire_des_key_new_with_version (data, key); + Desfire_des_key_new_with_version(data, key); } -void Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key) { - if ( key != NULL) { - key->type = T_DES; - memcpy (key->data, value, 8); - memcpy (key->data+8, value, 8); - update_key_schedules (key); - } +void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key) { + if (key != NULL) { + key->type = T_DES; + memcpy(key->data, value, 8); + memcpy(key->data + 8, value, 8); + update_key_schedules(key); + } } -void Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key) { +void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key) { uint8_t data[16]; - memcpy (data, value, 16); - for (int n=0; n < 8; n++) + memcpy(data, value, 16); + for (int n = 0; n < 8; n++) data[n] &= 0xfe; - for (int n=8; n < 16; n++) + for (int n = 8; n < 16; n++) data[n] |= 0x01; - Desfire_3des_key_new_with_version (data, key); + Desfire_3des_key_new_with_version(data, key); } -void Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key) { - if ( key != NULL ){ - key->type = T_3DES; - memcpy (key->data, value, 16); - memcpy (key->data + 16, value, 8); - update_key_schedules (key); - } +void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key) { + if (key != NULL) { + key->type = T_3DES; + memcpy(key->data, value, 16); + memcpy(key->data + 16, value, 8); + update_key_schedules(key); + } } -void Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key) { +void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key) { uint8_t data[24]; - memcpy (data, value, 24); - for (int n=0; n < 8; n++) + memcpy(data, value, 24); + for (int n = 0; n < 8; n++) data[n] &= 0xfe; - Desfire_3k3des_key_new_with_version (data, key); + Desfire_3k3des_key_new_with_version(data, key); } -void Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key) { - if ( key != NULL){ - key->type = T_3K3DES; - memcpy (key->data, value, 24); - update_key_schedules (key); - } +void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key) { + if (key != NULL) { + key->type = T_3K3DES; + memcpy(key->data, value, 24); + update_key_schedules(key); + } } - void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key) { - Desfire_aes_key_new_with_version (value, 0, key); +void Desfire_aes_key_new(const uint8_t value[16], desfirekey_t key) { + Desfire_aes_key_new_with_version(value, 0, key); } - void Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version, desfirekey_t key) { +void Desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version, desfirekey_t key) { - if (key != NULL) { - memcpy (key->data, value, 16); - key->type = T_AES; - key->aes_version = version; - } + if (key != NULL) { + memcpy(key->data, value, 16); + key->type = T_AES; + key->aes_version = version; + } } -uint8_t Desfire_key_get_version (desfirekey_t key) { +uint8_t Desfire_key_get_version(desfirekey_t key) { uint8_t version = 0; for (int n = 0; n < 8; n++) { @@ -103,54 +103,53 @@ uint8_t Desfire_key_get_version (desfirekey_t key) { return version; } -void Desfire_key_set_version (desfirekey_t key, uint8_t version) -{ +void Desfire_key_set_version(desfirekey_t key, uint8_t version) { for (int n = 0; n < 8; n++) { - uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n)); + uint8_t version_bit = ((version & (1 << (7 - n))) >> (7 - n)); key->data[n] &= 0xfe; key->data[n] |= version_bit; if (key->type == T_DES) { - key->data[n+8] = key->data[n]; + key->data[n + 8] = key->data[n]; } else { // Write ~version to avoid turning a 3DES key into a DES key - key->data[n+8] &= 0xfe; - key->data[n+8] |= ~version_bit; + key->data[n + 8] &= 0xfe; + key->data[n + 8] |= ~version_bit; } } } -void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) { +void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) { uint8_t buffer[24]; switch (authkey->type) { - case T_DES: - memcpy (buffer, rnda, 4); - memcpy (buffer+4, rndb, 4); - Desfire_des_key_new_with_version (buffer, key); - break; - case T_3DES: - memcpy (buffer, rnda, 4); - memcpy (buffer+4, rndb, 4); - memcpy (buffer+8, rnda+4, 4); - memcpy (buffer+12, rndb+4, 4); - Desfire_3des_key_new_with_version (buffer, key); - break; - case T_3K3DES: - memcpy (buffer, rnda, 4); - memcpy (buffer+4, rndb, 4); - memcpy (buffer+8, rnda+6, 4); - memcpy (buffer+12, rndb+6, 4); - memcpy (buffer+16, rnda+12, 4); - memcpy (buffer+20, rndb+12, 4); - Desfire_3k3des_key_new (buffer, key); - break; - case T_AES: - memcpy (buffer, rnda, 4); - memcpy (buffer+4, rndb, 4); - memcpy (buffer+8, rnda+12, 4); - memcpy (buffer+12, rndb+12, 4); - Desfire_aes_key_new (buffer, key); - break; + case T_DES: + memcpy(buffer, rnda, 4); + memcpy(buffer + 4, rndb, 4); + Desfire_des_key_new_with_version(buffer, key); + break; + case T_3DES: + memcpy(buffer, rnda, 4); + memcpy(buffer + 4, rndb, 4); + memcpy(buffer + 8, rnda + 4, 4); + memcpy(buffer + 12, rndb + 4, 4); + Desfire_3des_key_new_with_version(buffer, key); + break; + case T_3K3DES: + memcpy(buffer, rnda, 4); + memcpy(buffer + 4, rndb, 4); + memcpy(buffer + 8, rnda + 6, 4); + memcpy(buffer + 12, rndb + 6, 4); + memcpy(buffer + 16, rnda + 12, 4); + memcpy(buffer + 20, rndb + 12, 4); + Desfire_3k3des_key_new(buffer, key); + break; + case T_AES: + memcpy(buffer, rnda, 4); + memcpy(buffer + 4, rndb, 4); + memcpy(buffer + 8, rnda + 12, 4); + memcpy(buffer + 12, rndb + 12, 4); + Desfire_aes_key_new(buffer, key); + break; } -} \ No newline at end of file +} diff --git a/armsrc/desfire_key.h b/armsrc/desfire_key.h index 4e6fdaea9..4fc02854e 100644 --- a/armsrc/desfire_key.h +++ b/armsrc/desfire_key.h @@ -6,15 +6,15 @@ #include "iso14443a.h" #include "desfire.h" //#include "mifare.h" // iso14a_card_select_t struct -void Desfire_des_key_new (const uint8_t value[8], desfirekey_t key); -void Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key); -void Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key); -void Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key); -void Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key); -void Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key); -void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key); -void Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version,desfirekey_t key); -uint8_t Desfire_key_get_version (desfirekey_t key); -void Desfire_key_set_version (desfirekey_t key, uint8_t version); -void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key); -#endif \ No newline at end of file +void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key); +void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key); +void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key); +void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key); +void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key); +void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key); +void Desfire_aes_key_new(const uint8_t value[16], desfirekey_t key); +void Desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version, desfirekey_t key); +uint8_t Desfire_key_get_version(desfirekey_t key); +void Desfire_key_set_version(desfirekey_t key, uint8_t version); +void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key); +#endif diff --git a/armsrc/epa.c b/armsrc/epa.c index 5a8fdc8bb..fabeec6d2 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -21,41 +21,41 @@ static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6}; // General Authenticate (request encrypted nonce) WITHOUT the Le at the end static const uint8_t apdu_general_authenticate_pace_get_nonce[] = { - 0x10, // CLA - 0x86, // INS - 0x00, // P1 - 0x00, // P2 - 0x02, // Lc - 0x7C, // Type: Dynamic Authentication Data - 0x00, // Length: 0 bytes + 0x10, // CLA + 0x86, // INS + 0x00, // P1 + 0x00, // P2 + 0x02, // Lc + 0x7C, // Type: Dynamic Authentication Data + 0x00, // Length: 0 bytes }; // MSE: Set AT (only CLA, INS, P1 and P2) static const uint8_t apdu_mse_set_at_start[] = { - 0x00, // CLA - 0x22, // INS - 0xC1, // P1 - 0xA4, // P2 + 0x00, // CLA + 0x22, // INS + 0xC1, // P1 + 0xA4, // P2 }; // SELECT BINARY with the ID for EF.CardAccess static const uint8_t apdu_select_binary_cardaccess[] = { - 0x00, // CLA - 0xA4, // INS - 0x02, // P1 - 0x0C, // P2 - 0x02, // Lc - 0x01, // ID - 0x1C // ID + 0x00, // CLA + 0xA4, // INS + 0x02, // P1 + 0x0C, // P2 + 0x02, // Lc + 0x01, // ID + 0x1C // ID }; // READ BINARY static const uint8_t apdu_read_binary[] = { - 0x00, // CLA - 0xB0, // INS - 0x00, // P1 - 0x00, // P2 - 0x38 // Le + 0x00, // CLA + 0xB0, // INS + 0x00, // P1 + 0x00, // P2 + 0x38 // Le }; @@ -84,14 +84,14 @@ static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75]; 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; + 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} + {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 @@ -103,30 +103,27 @@ 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, response); - break; - case 'b': - return iso14443b_apdu(apdu, length, response); - break; - default: - return 0; - break; - } +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 //----------------------------------------------------------------------------- -void EPA_Finish() -{ - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - iso_type = 0; +void EPA_Finish() { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + iso_type = 0; } //----------------------------------------------------------------------------- @@ -144,70 +141,65 @@ void EPA_Finish() //----------------------------------------------------------------------------- size_t EPA_Parse_CardAccess(uint8_t *data, size_t length, - pace_version_info_t *pace_info) -{ - size_t index = 0; + 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 - if ((data[index - 1] & 0x80) != 0) { - index += (data[index-1] & 0x7F); - } - } - // OID - else if (data[index] == 0x06) { - // is this a PACE OID? - if (data[index + 1] == 0x0A // length matches - && memcmp(data + index + 2, - oid_pace_start, - sizeof(oid_pace_start)) == 0 // content matches - && pace_info != NULL) - { - // first, clear the pace_info struct - memset(pace_info, 0, sizeof(pace_version_info_t)); - memcpy(pace_info->oid, data + index + 2, sizeof(pace_info->oid)); - // a PACE OID is followed by the version - index += data[index + 1] + 2; - if (data[index] == 02 && data[index + 1] == 01) { - pace_info->version = data[index + 2]; - index += 3; - } - else { - return index; - } - // after that there might(!) be the parameter ID - if (data[index] == 02 && data[index + 1] == 01) { - pace_info->parameter_id = data[index + 2]; - index += 3; - } - } - else { - // skip this OID - index += 2 + data[index + 1]; - } - } - // if the length is 0, something is wrong - // TODO: This needs to be extended to support long tags - else if (data[index + 1] == 0) { - return index; - } - else { - // skip this part - // TODO: This needs to be extended to support long tags - // TODO: This needs to be extended to support unknown elements with - // a size > 0x7F - index += 2 + data[index + 1]; - } - } + 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 + if ((data[index - 1] & 0x80) != 0) { + index += (data[index - 1] & 0x7F); + } + } + // OID + else if (data[index] == 0x06) { + // is this a PACE OID? + if (data[index + 1] == 0x0A // length matches + && memcmp(data + index + 2, + oid_pace_start, + sizeof(oid_pace_start)) == 0 // content matches + && pace_info != NULL) { + // first, clear the pace_info struct + memset(pace_info, 0, sizeof(pace_version_info_t)); + memcpy(pace_info->oid, data + index + 2, sizeof(pace_info->oid)); + // a PACE OID is followed by the version + index += data[index + 1] + 2; + if (data[index] == 02 && data[index + 1] == 01) { + pace_info->version = data[index + 2]; + index += 3; + } else { + return index; + } + // after that there might(!) be the parameter ID + if (data[index] == 02 && data[index + 1] == 01) { + pace_info->parameter_id = data[index + 2]; + index += 3; + } + } else { + // skip this OID + index += 2 + data[index + 1]; + } + } + // if the length is 0, something is wrong + // TODO: This needs to be extended to support long tags + else if (data[index + 1] == 0) { + return index; + } else { + // skip this part + // TODO: This needs to be extended to support long tags + // TODO: This needs to be extended to support unknown elements with + // a size > 0x7F + 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; + // 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; } //----------------------------------------------------------------------------- @@ -215,126 +207,125 @@ size_t EPA_Parse_CardAccess(uint8_t *data, // Returns -1 on failure or the length of the data on success // TODO: for the moment this sends only 1 APDU regardless of the requested length //----------------------------------------------------------------------------- -int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) -{ - // the response APDU of the card - // since the card doesn't always care for the expected length we send it, - // we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame) - uint8_t response_apdu[262]; - int rapdu_length = 0; +int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) { + // the response APDU of the card + // since the card doesn't always care for the expected length we send it, + // 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, - sizeof(apdu_select_binary_cardaccess), - response_apdu); - if (rapdu_length < 6 - || response_apdu[rapdu_length - 4] != 0x90 - || response_apdu[rapdu_length - 3] != 0x00) - { - DbpString("Failed to select EF.CardAccess!"); - return -1; - } + // select the file EF.CardAccess + rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess, + sizeof(apdu_select_binary_cardaccess), + response_apdu); + 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, - 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; - } + // read the file + rapdu_length = EPA_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; - to_copy = to_copy < max_length ? to_copy : max_length; - memcpy(buffer, response_apdu+2, to_copy); - return to_copy; + // copy the content into the buffer + // length of data available: apdu_length - 4 (ISO frame) - 2 (SW) + size_t to_copy = rapdu_length - 6; + to_copy = to_copy < max_length ? to_copy : max_length; + memcpy(buffer, response_apdu + 2, to_copy); + return to_copy; } //----------------------------------------------------------------------------- // Abort helper function for EPA_PACE_Collect_Nonce // sets relevant data in ack, sends the response //----------------------------------------------------------------------------- -static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) -{ - // power down the field - EPA_Finish(); +static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) { + // power down the field + EPA_Finish(); - // send the USB packet - cmd_send(CMD_ACK,step,func_return,0,0,0); + // send the USB packet + reply_old(CMD_ACK, step, func_return, 0, 0, 0); } //----------------------------------------------------------------------------- // Acquire one encrypted PACE nonce //----------------------------------------------------------------------------- -void EPA_PACE_Collect_Nonce(UsbCommand *c) -{ - /* - * ack layout: - * arg: - * 1. element - * step where the error occured or 0 if no error occured +void EPA_PACE_Collect_Nonce(PacketCommandNG *c) { + /* + * ack layout: + * arg: + * 1. element + * step where the error occured or 0 if no error occured * 2. element * return code of the last executed function - * d: - * Encrypted nonce - */ + * d: + * Encrypted nonce + */ - // return value of a function - int func_return = 0; + // return value of a function + int func_return = 0; - // set up communication - func_return = EPA_Setup(); - if (func_return != 0) { - EPA_PACE_Collect_Nonce_Abort(1, func_return); - return; - } + // set up communication + func_return = EPA_Setup(); + if (func_return != 0) { + EPA_PACE_Collect_Nonce_Abort(1, func_return); + return; + } - // read the CardAccess file - // this array will hold the CardAccess file - uint8_t card_access[256] = {0}; - int card_access_length = EPA_Read_CardAccess(card_access, 256); - // the response has to be at least this big to hold the OID - if (card_access_length < 18) { - EPA_PACE_Collect_Nonce_Abort(2, card_access_length); - return; - } + // read the CardAccess file + // this array will hold the CardAccess file + uint8_t card_access[256] = {0}; + int card_access_length = EPA_Read_CardAccess(card_access, 256); + // the response has to be at least this big to hold the OID + if (card_access_length < 18) { + EPA_PACE_Collect_Nonce_Abort(2, card_access_length); + return; + } - // this will hold the PACE info of the card - pace_version_info_t pace_version_info; - // search for the PACE OID - func_return = EPA_Parse_CardAccess(card_access, - card_access_length, - &pace_version_info); - if (func_return != 0 || pace_version_info.version == 0) { - EPA_PACE_Collect_Nonce_Abort(3, func_return); - return; - } + // this will hold the PACE info of the card + pace_version_info_t pace_version_info; + // search for the PACE OID + func_return = EPA_Parse_CardAccess(card_access, + card_access_length, + &pace_version_info); + if (func_return != 0 || pace_version_info.version == 0) { + 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); + // 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); + // check if the command succeeded + if (func_return != 0) { + EPA_PACE_Collect_Nonce_Abort(4, func_return); + return; + } - // now get the nonce - uint8_t nonce[256] = {0}; - uint8_t requested_size = (uint8_t)c->arg[0]; - func_return = EPA_PACE_Get_Nonce(requested_size, nonce); - // check if the command succeeded - if (func_return < 0) - { - EPA_PACE_Collect_Nonce_Abort(4, func_return); - return; - } + // now get the nonce + uint8_t nonce[256] = {0}; + uint8_t requested_size = (uint8_t)c->oldarg[0]; + func_return = EPA_PACE_Get_Nonce(requested_size, nonce); + // check if the command succeeded + if (func_return < 0) { + EPA_PACE_Collect_Nonce_Abort(5, func_return); + return; + } - // all done, return - EPA_Finish(); + // all done, return + EPA_Finish(); - // save received information - cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); + // save received information + reply_old(CMD_ACK, 0, func_return, 0, nonce, func_return); } //----------------------------------------------------------------------------- @@ -345,210 +336,199 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) // Returns the actual size of the nonce on success or a less-than-zero error // code on failure. //----------------------------------------------------------------------------- -int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) -{ - // build the APDU - uint8_t apdu[sizeof(apdu_general_authenticate_pace_get_nonce) + 1]; - // copy the constant part - memcpy(apdu, - apdu_general_authenticate_pace_get_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; +int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) { + // build the APDU + uint8_t apdu[sizeof(apdu_general_authenticate_pace_get_nonce) + 1]; + // copy the constant part + memcpy(apdu, + apdu_general_authenticate_pace_get_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, - sizeof(apdu), - response_apdu); - // check if the command succeeded - if (send_return < 6 - || response_apdu[send_return - 4] != 0x90 - || response_apdu[send_return - 3] != 0x00) - { - return -1; - } + // send it + uint8_t response_apdu[262]; + int send_return = EPA_APDU(apdu, + sizeof(apdu), + response_apdu); + // check if the command succeeded + if (send_return < 6 + || response_apdu[send_return - 4] != 0x90 + || response_apdu[send_return - 3] != 0x00) { + return -1; + } - // if there is no nonce in the RAPDU, return here - if (send_return < 10) - { - // no error - return 0; - } - // get the actual length of the nonce - uint8_t nonce_length = response_apdu[5]; - if (nonce_length > send_return - 10) - { - nonce_length = send_return - 10; - } - // copy the nonce - memcpy(nonce, response_apdu + 6, nonce_length); + // if there is no nonce in the RAPDU, return here + if (send_return < 10) { + // no error + return 0; + } + // get the actual length of the nonce + uint8_t nonce_length = response_apdu[5]; + if (nonce_length > send_return - 10) { + nonce_length = send_return - 10; + } + // copy the nonce + memcpy(nonce, response_apdu + 6, nonce_length); - return nonce_length; + return nonce_length; } //----------------------------------------------------------------------------- // Initializes the PACE protocol by performing the "MSE: Set AT" step // Returns 0 on success or a non-zero error code on failure //----------------------------------------------------------------------------- -int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) -{ - // create the MSE: Set AT APDU - uint8_t apdu[23]; - // the minimum length (will be increased as more data is added) - size_t apdu_length = 20; - // copy the constant part - memcpy(apdu, - apdu_mse_set_at_start, - sizeof(apdu_mse_set_at_start)); - // type: OID - apdu[5] = 0x80; - // length of the OID - apdu[6] = sizeof(pace_version_info.oid); - // copy the OID - memcpy(apdu + 7, - pace_version_info.oid, - sizeof(pace_version_info.oid)); - // type: password - apdu[17] = 0x83; - // length: 1 - apdu[18] = 1; - // password - apdu[19] = password; - // if standardized domain parameters are used, copy the ID - if (pace_version_info.parameter_id != 0) { - apdu_length += 3; - // type: domain parameter - apdu[20] = 0x84; - // length: 1 - apdu[21] = 1; - // copy the parameter ID - apdu[22] = pace_version_info.parameter_id; - } - // now set Lc to the actual length - apdu[4] = apdu_length - 5; - // send it - uint8_t response_apdu[6]; - int send_return = EPA_APDU(apdu, - apdu_length, - response_apdu); - // check if the command succeeded - if (send_return != 6 - || response_apdu[send_return - 4] != 0x90 - || response_apdu[send_return - 3] != 0x00) - { - return 1; - } - return 0; +int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) { + // create the MSE: Set AT APDU + uint8_t apdu[23]; + // the minimum length (will be increased as more data is added) + size_t apdu_length = 20; + // copy the constant part + memcpy(apdu, + apdu_mse_set_at_start, + sizeof(apdu_mse_set_at_start)); + // type: OID + apdu[5] = 0x80; + // length of the OID + apdu[6] = sizeof(pace_version_info.oid); + // copy the OID + memcpy(apdu + 7, + pace_version_info.oid, + sizeof(pace_version_info.oid)); + // type: password + apdu[17] = 0x83; + // length: 1 + apdu[18] = 1; + // password + apdu[19] = password; + // if standardized domain parameters are used, copy the ID + if (pace_version_info.parameter_id != 0) { + apdu_length += 3; + // type: domain parameter + apdu[20] = 0x84; + // length: 1 + apdu[21] = 1; + // copy the parameter ID + apdu[22] = pace_version_info.parameter_id; + } + // now set Lc to the actual length + apdu[4] = apdu_length - 5; + // send it + uint8_t response_apdu[6]; + int send_return = EPA_APDU(apdu, + apdu_length, + response_apdu); + // check if the command succeeded + if (send_return != 6 + || response_apdu[send_return - 4] != 0x90 + || response_apdu[send_return - 3] != 0x00) { + return 1; + } + 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}; +void EPA_PACE_Replay(PacketCommandNG *c) { + uint32_t timings[ARRAYLEN(apdu_lengths_replay)] = {0}; - // if an APDU has been passed, 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); - } - 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; - } + // if an APDU has been passed, save it + if (c->oldarg[0] != 0) { + // make sure it's not too big + if (c->oldarg[2] > apdus_replay[c->oldarg[0] - 1].len) { + reply_old(CMD_ACK, 1, 0, 0, NULL, 0); + } + memcpy(apdus_replay[c->oldarg[0] - 1].data + c->oldarg[1], + c->data.asBytes, + c->oldarg[2]); + // save/update APDU length + if (c->oldarg[1] == 0) { + apdu_lengths_replay[c->oldarg[0] - 1] = c->oldarg[2]; + } else { + apdu_lengths_replay[c->oldarg[0] - 1] += c->oldarg[2]; + } + reply_old(CMD_ACK, 0, 0, 0, NULL, 0); + return; + } - // return value of a function - int func_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; - } + // set up communication + func_return = EPA_Setup(); + if (func_return != 0) { + EPA_Finish(); + reply_old(CMD_ACK, 2, func_return, 0, NULL, 0); + return; + } - // increase the timeout (at least some cards really do need this!)///////////// - // iso14a_set_timeout(0x0003FFFF); + // increase the timeout (at least some cards really do need this!)///////////// + // iso14a_set_timeout(0x0003FFFF); - // response APDU - uint8_t response_apdu[300] = {0}; + // 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; + // 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(); + reply_old(CMD_ACK, 3 + i, func_return, 0, timings, 20); + return; + } + } + EPA_Finish(); + reply_old(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() -{ - int return_code = 0; - uint8_t uid[10]; - uint8_t pps_response[3]; - uint8_t pps_response_par[1]; - iso14a_card_select_t card_a_info; - iso14b_card_select_t card_b_info; +int EPA_Setup() { + uint8_t uid[10]; + iso14a_card_select_t card_a_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_a_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; - } + // first, look for type A cards + // power up the field + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + // select the card + int return_code = iso14443a_select_card(uid, &card_a_info, NULL, true, 0, false); + if (return_code == 1) { + uint8_t pps_response[3]; + uint8_t pps_response_par[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; + } - // 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( &card_b_info ); - if (return_code == 1) { - Dbprintf("ISO 14443 Type B"); - iso_type = 'b'; - return 0; - } - Dbprintf("No card found."); - return 1; + // if we're here, there is no type A card, so we look for type B + // power up the field + iso14443b_setup(); + iso14b_card_select_t card_b_info; + // select the card + return_code = iso14443b_select_card(&card_b_info); + if (return_code == 0) { + Dbprintf("ISO 14443 Type B"); + iso_type = 'b'; + return 0; + } + Dbprintf("No card found."); + return 1; } diff --git a/armsrc/epa.h b/armsrc/epa.h index 550af8200..a0701ab57 100644 --- a/armsrc/epa.h +++ b/armsrc/epa.h @@ -18,9 +18,9 @@ // this struct is used by EPA_Parse_CardAccess and contains info about the // PACE protocol supported by the chip typedef struct { - uint8_t oid[10]; - uint8_t version; - uint8_t parameter_id; + uint8_t oid[10]; + uint8_t version; + uint8_t parameter_id; } pace_version_info_t; // note: EPA_PACE_Collect_Nonce and EPA_PACE_Replay are declared in apps.h diff --git a/armsrc/felica.c b/armsrc/felica.c index b25653d80..48b6f4464 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -2,9 +2,9 @@ #include "apps.h" #include "BigBuf.h" #include "util.h" -#include "usb_cdc.h" // for usb_poll_validate_length +#include "usb_cdc.h" // for usb_poll_validate_length #include "protocols.h" -#include "crc16.h" // crc16 ccitt +#include "crc16.h" // crc16 ccitt // FeliCa timings // minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56Mhz) cycles @@ -16,40 +16,38 @@ # define FELICA_FRAME_DELAY_TIME (2672/16 + 1) #endif #ifndef DELAY_AIR2ARM_AS_READER -#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) +#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) #endif #ifndef DELAY_ARM2AIR_AS_READER #define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) #endif // CRC skips two first sync bits in data buffer -#define AddCrc(data, len) compute_crc(CRC_FELICA, (data)+2, (len),(data)+(len)+2, (data)+(len)+3) +#define AddCrc(data, len) compute_crc(CRC_FELICA, (data)+2, (len),(data)+(len)+2, (data)+(len)+3) static uint32_t felica_timeout; static uint32_t felica_nexttransfertime; static uint32_t felica_lasttime_prox2air_start; -static void felica_setup(uint8_t fpga_minor_mode); +static void iso18092_setup(uint8_t fpga_minor_mode); static uint8_t felica_select_card(felica_card_select_t *card); -static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed); +static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed); bool WaitForFelicaReply(uint16_t maxbytes); -void felica_set_timeout(uint32_t timeout) { - felica_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2; +void iso18092_set_timeout(uint32_t timeout) { + felica_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) + 2; } -uint32_t felica_get_timeout(void) { - return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2; +uint32_t iso18092_get_timeout(void) { + return felica_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) - 2; } -//random service RW: 0x0009 -//random service RO: 0x000B -#ifndef NFC_MAX_FRAME_SIZE - #define NFC_MAX_FRAME_SIZE 260 +#ifndef FELICA_MAX_FRAME_SIZE +#define FELICA_MAX_FRAME_SIZE 260 #endif -//structure to hold outgoing NFC frame -static uint8_t frameSpace[NFC_MAX_FRAME_SIZE+4]; +//structure to hold outgoing NFC frame +static uint8_t frameSpace[FELICA_MAX_FRAME_SIZE + 4]; //structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames static struct { @@ -64,128 +62,128 @@ static struct { uint16_t shiftReg; //for synchronization and offset calculation int posCnt; - bool crc_ok; + bool crc_ok; int rem_len; uint16_t len; uint8_t byte_offset; - uint8_t *framebytes; - //should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc - // 0,1 -> SYNC, 2 - len, 3-(len+1)->data, then crc -} NFCFrame; + uint8_t *framebytes; +//should be enough. maxlen is 255, 254 for data, 2 for sync, 2 for crc +// 0,1 -> SYNC, 2 - len, 3-(len+1)->data, then crc +} FelicaFrame; //b2 4d is SYNC, 45645 in 16-bit notation, 10110010 01001101 binary. Frame will not start filling until this is shifted in //bit order in byte -reverse, I guess? [((bt>>0)&1),((bt>>1)&1),((bt>>2)&1),((bt>>3)&1),((bt>>4)&1),((bt>>5)&1),((bt>>6)&1),((bt>>7)&1)] -at least in the mode that I read those in #ifndef SYNC_16BIT -# define SYNC_16BIT 0x4DB2 +# define SYNC_16BIT 0xB24D #endif -static void NFCFrameReset() { - NFCFrame.state = STATE_UNSYNCD; - NFCFrame.posCnt = 0; - NFCFrame.crc_ok = false; - NFCFrame.byte_offset = 0; +static void FelicaFrameReset() { + FelicaFrame.state = STATE_UNSYNCD; + FelicaFrame.posCnt = 0; + FelicaFrame.crc_ok = false; + FelicaFrame.byte_offset = 0; } -static void NFCInit(uint8_t *data) { - NFCFrame.framebytes = data; - NFCFrameReset(); +static void FelicaFrameinit(uint8_t *data) { + FelicaFrame.framebytes = data; + FelicaFrameReset(); } //shift byte into frame, reversing it at the same time -static void shiftInByte(uint8_t bt) { - uint8_t j; - for(j=0; j < NFCFrame.byte_offset; j++) { - NFCFrame.framebytes[NFCFrame.posCnt] = ( NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); +static void shiftInByte(uint8_t bt) { + uint8_t j; + for (j = 0; j < FelicaFrame.byte_offset; j++) { + FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt] << 1) + (bt & 1); bt >>= 1; } - NFCFrame.posCnt++; - NFCFrame.rem_len--; - for(j = NFCFrame.byte_offset; j<8; j++) { - NFCFrame.framebytes[NFCFrame.posCnt] = (NFCFrame.framebytes[NFCFrame.posCnt]<<1 ) + (bt & 1); + FelicaFrame.posCnt++; + FelicaFrame.rem_len--; + for (j = FelicaFrame.byte_offset; j < 8; j++) { + FelicaFrame.framebytes[FelicaFrame.posCnt] = (FelicaFrame.framebytes[FelicaFrame.posCnt] << 1) + (bt & 1); bt >>= 1; } } -static void ProcessNFCByte(uint8_t bt) { - switch (NFCFrame.state) { - case STATE_UNSYNCD: { - //almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not alsways the case - if (bt > 0) { - NFCFrame.shiftReg = reflect8(bt); - NFCFrame.state = STATE_TRYING_SYNC; - } - break; - } - case STATE_TRYING_SYNC: { - if (bt == 0) { - //desync - NFCFrame.shiftReg = bt; - NFCFrame.state = STATE_UNSYNCD; - } else { - for (uint8_t i=0; i<8; i++) { - - if (NFCFrame.shiftReg == SYNC_16BIT) { - //SYNC done! - NFCFrame.state = STATE_GET_LENGTH; - NFCFrame.framebytes[0] = 0xb2; - NFCFrame.framebytes[1] = 0x4d; //write SYNC - NFCFrame.byte_offset = i; - //shift in remaining byte, slowly... - for(uint8_t j=i; j<8; j++) { - NFCFrame.framebytes[2] = (NFCFrame.framebytes[2] << 1) + (bt & 1); - bt >>= 1; - } - - NFCFrame.posCnt = 2; - if (i==0) - break; - } - NFCFrame.shiftReg = (NFCFrame.shiftReg << 1) + (bt & 1); - bt >>= 1; - } +static void Process18092Byte(uint8_t bt) { + switch (FelicaFrame.state) { + case STATE_UNSYNCD: { + //almost any nonzero byte can be start of SYNC. SYNC should be preceded by zeros, but that is not alsways the case + if (bt > 0) { + FelicaFrame.shiftReg = reflect8(bt); + FelicaFrame.state = STATE_TRYING_SYNC; + } + break; + } + case STATE_TRYING_SYNC: { + if (bt == 0) { + //desync + FelicaFrame.shiftReg = bt; + FelicaFrame.state = STATE_UNSYNCD; + } else { + for (uint8_t i = 0; i < 8; i++) { - //that byte was last byte of sync - if (NFCFrame.shiftReg == SYNC_16BIT) { - //Force SYNC on next byte - NFCFrame.state = STATE_GET_LENGTH; - NFCFrame.framebytes[0] = 0xb2; - NFCFrame.framebytes[1] = 0x4d; - NFCFrame.byte_offset = 0; - NFCFrame.posCnt = 1; - } - } - break; - } - case STATE_GET_LENGTH: { - shiftInByte(bt); - NFCFrame.rem_len = NFCFrame.framebytes[2] - 1; - NFCFrame.len = NFCFrame.framebytes[2] + 4; //with crc and sync - NFCFrame.state = STATE_GET_DATA; - break; - } - case STATE_GET_DATA: { - shiftInByte(bt); - if (NFCFrame.rem_len <= 0) { - NFCFrame.state = STATE_GET_CRC; - NFCFrame.rem_len = 2; - } - break; - } - case STATE_GET_CRC: { - shiftInByte(bt); + if (FelicaFrame.shiftReg == SYNC_16BIT) { + //SYNC done! + FelicaFrame.state = STATE_GET_LENGTH; + FelicaFrame.framebytes[0] = 0xb2; + FelicaFrame.framebytes[1] = 0x4d; + FelicaFrame.byte_offset = i; + //shift in remaining byte, slowly... + for (uint8_t j = i; j < 8; j++) { + FelicaFrame.framebytes[2] = (FelicaFrame.framebytes[2] << 1) + (bt & 1); + bt >>= 1; + } - if ( NFCFrame.rem_len <= 0 ) { - // skip sync 2bytes. IF ok, residue should be 0x0000 - NFCFrame.crc_ok = check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2); - NFCFrame.state = STATE_FULL; - NFCFrame.rem_len = 0; - if (MF_DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (NFCFrame.crc_ok) ? "OK" : "No" ); - } - break; - } - case STATE_FULL: //ignore byte. Don't forget to clear frame to receive next one... - default: - break; - } + FelicaFrame.posCnt = 2; + if (i == 0) + break; + } + FelicaFrame.shiftReg = (FelicaFrame.shiftReg << 1) + (bt & 1); + bt >>= 1; + } + + //that byte was last byte of sync + if (FelicaFrame.shiftReg == SYNC_16BIT) { + //Force SYNC on next byte + FelicaFrame.state = STATE_GET_LENGTH; + FelicaFrame.framebytes[0] = 0xb2; + FelicaFrame.framebytes[1] = 0x4d; + FelicaFrame.byte_offset = 0; + FelicaFrame.posCnt = 1; + } + } + break; + } + case STATE_GET_LENGTH: { + shiftInByte(bt); + FelicaFrame.rem_len = FelicaFrame.framebytes[2] - 1; + FelicaFrame.len = FelicaFrame.framebytes[2] + 4; //with crc and sync + FelicaFrame.state = STATE_GET_DATA; + break; + } + case STATE_GET_DATA: { + shiftInByte(bt); + if (FelicaFrame.rem_len <= 0) { + FelicaFrame.state = STATE_GET_CRC; + FelicaFrame.rem_len = 2; + } + break; + } + case STATE_GET_CRC: { + shiftInByte(bt); + + if (FelicaFrame.rem_len <= 0) { + // skip sync 2bytes. IF ok, residue should be 0x0000 + FelicaFrame.crc_ok = check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2); + FelicaFrame.state = STATE_FULL; + FelicaFrame.rem_len = 0; + if (DBGLEVEL > 3) Dbprintf("[+] got 2 crc bytes [%s]", (FelicaFrame.crc_ok) ? "OK" : "No"); + } + break; + } + case STATE_FULL: //ignore byte. Don't forget to clear frame to receive next one... + default: + break; + } } /* Perform FeliCa polling card @@ -194,64 +192,64 @@ static void ProcessNFCByte(uint8_t bt) { */ static uint8_t felica_select_card(felica_card_select_t *card) { - // POLL command - // 0xB2 0x4B = sync code - // 0x06 = len - // 0x00 = rfu - // 0xff = system service - // 0xff = system service - // 0x00 = - // b7 = automatic switching of data rate - // b6-b2 = reserved - // b1 = fc/32 (414kbps) - // b0 = fc/64 (212kbps) - // 0x00 = timeslot - // 0x09 0x21 = crc - static uint8_t poll[10] = {0xb2,0x4d,0x06,0x00,0xFF,0xFF,0x00,0x00,0x09,0x21}; - - int len = 20; - - // We try 20 times, or if answer was received. - do { - // end-of-reception response packet data, wait approx. 501μs - // end-of-transmission command packet data, wait approx. 197μs - // polling card - TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0); + // POLL command + // 0xB2 0x4B = sync code + // 0x06 = len + // 0x00 = rfu + // 0xff = system service + // 0xff = system service + // 0x00 = + // b7 = automatic switching of data rate + // b6-b2 = reserved + // b1 = fc/32 (414kbps) + // b0 = fc/64 (212kbps) + // 0x00 = timeslot + // 0x09 0x21 = crc + static uint8_t poll[10] = {0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xFF, 0xFF, 0x00, 0x00, 0x09, 0x21}; - // polling card, break if success - if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) - break; - - WDT_HIT(); - - } while (--len); - - // timed-out - if ( len == 0 ) - return 1; - - // wrong answer - if (NFCFrame.framebytes[3] != FELICA_POLL_ACK) - return 2; - - // VALIDATE CRC residue is 0, hence if crc is a value it failed. - if (!check_crc(CRC_FELICA, NFCFrame.framebytes+2, NFCFrame.len-2)) - return 3; - - // copy UID - // idm 8 - if (card) { - memcpy(card->IDm, NFCFrame.framebytes + 4, 8); - memcpy(card->PMm, NFCFrame.framebytes + 4 + 8, 8); - //memcpy(card->servicecode, NFCFrame.framebytes + 4 + 8 + 8, 2); - memcpy(card->code, card->IDm, 2); - memcpy(card->uid, card->IDm + 2, 6); - memcpy(card->iccode, card->PMm, 2); - memcpy(card->mrt, card->PMm+2, 6); - - } - // more status bytes? - return 0; + int len = 20; + + // We try 20 times, or if answer was received. + do { + // end-of-reception response packet data, wait approx. 501μs + // end-of-transmission command packet data, wait approx. 197μs + // polling card + TransmitFor18092_AsReader(poll, sizeof(poll), NULL, 1, 0); + + // polling card, break if success + if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) + break; + + WDT_HIT(); + + } while (--len); + + // timed-out + if (len == 0) + return 1; + + // wrong answer + if (FelicaFrame.framebytes[3] != FELICA_POLL_ACK) + return 2; + + // VALIDATE CRC residue is 0, hence if crc is a value it failed. + if (!check_crc(CRC_FELICA, FelicaFrame.framebytes + 2, FelicaFrame.len - 2)) + return 3; + + // copy UID + // idm 8 + if (card) { + memcpy(card->IDm, FelicaFrame.framebytes + 4, 8); + memcpy(card->PMm, FelicaFrame.framebytes + 4 + 8, 8); + //memcpy(card->servicecode, FelicaFrame.framebytes + 4 + 8 + 8, 2); + memcpy(card->code, card->IDm, 2); + memcpy(card->uid, card->IDm + 2, 6); + memcpy(card->iccode, card->PMm, 2); + memcpy(card->mrt, card->PMm + 2, 6); + + } + // more status bytes? + return 0; } // poll-0: 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21, @@ -259,124 +257,124 @@ static uint8_t felica_select_card(felica_card_select_t *card) { // poll-1 (reply with available system codes - NFC Tag3 specs, IIRC): 0xb2,0x4d,0x06,0x00,0xff,0xff,0x01,0x00,0x3a,0x10 // resp: 0xb2,0x4d,0x14,0x01, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0x0c,0xe2, // page-req: 0xb2,0x4d,0x10,0x06, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x01, 0x0b,0x00, 0x01, 0x80,0x00, 0x2e,0xb3, -// page-req: 0x06, IDm(8), ServiceNum(1),Slist(2*num) BLocknum (1) BLockids(2-3*num) +// page-req: 0x06, IDm(8), ServiceNum(1),Slist(2*num) BLocknum (1) BLockids(2-3*num) // page-resp: 0xb2,0x4d,0x1d,0x07, 0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX,0xXX, 0x00, 0x00, 0x01, 0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23, 0xcb,0x6e, -// builds a readblock frame for felica lite(s). Using SERVICE: SERVICE_FELICA_LITE_READONLY -// Felica standard has a different file system, AFAIK, +// builds a readblock frame for felica lite(s). Using SERVICE: SERVICE_FELICA_LITE_READONLY +// Felica standard has a different file system, AFAIK, // 8-byte IDm, number of blocks, blocks numbers // number of blocks limited to 4 for FelicaLite(S) -static void BuildFliteRdblk(uint8_t* idm, int blocknum, uint16_t *blocks ) { +static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) { if (blocknum > 4 || blocknum <= 0) - Dbprintf("Invalid number of blocks, %d. Up to 4 are allowed.", blocknum); - + Dbprintf("Invalid number of blocks, %d != 4", blocknum); + uint8_t c = 0, i = 0; - + frameSpace[c++] = 0xb2; frameSpace[c++] = 0x4d; - - c++; //set length later - - frameSpace[c++] = FELICA_RDBLK_REQ; //command number - - //card IDm, from poll - frameSpace[c++] = idm[0]; - frameSpace[c++] = idm[1]; - frameSpace[c++] = idm[2]; - frameSpace[c++] = idm[3]; - frameSpace[c++] = idm[4]; - frameSpace[c++] = idm[5]; - frameSpace[c++] = idm[6]; - frameSpace[c++] = idm[7]; - //number of services - frameSpace[c++] = 0x01; - - //service code - frameSpace[c++] = (SERVICE_FELICA_LITE_READONLY >> 8); + c++; //set length later + + frameSpace[c++] = FELICA_RDBLK_REQ; //command number + + //card IDm, from poll + frameSpace[c++] = idm[0]; + frameSpace[c++] = idm[1]; + frameSpace[c++] = idm[2]; + frameSpace[c++] = idm[3]; + frameSpace[c++] = idm[4]; + frameSpace[c++] = idm[5]; + frameSpace[c++] = idm[6]; + frameSpace[c++] = idm[7]; + + //number of services + frameSpace[c++] = 0x01; + + //service code + frameSpace[c++] = (SERVICE_FELICA_LITE_READONLY >> 8); frameSpace[c++] = SERVICE_FELICA_LITE_READONLY & 0xFF; - //number of blocks + //number of blocks frameSpace[c++] = blocknum; - for (i=0; i < blocknum; i++) { + for (i = 0; i < blocknum; i++) { - //3-byte block - if (blocks[i] >= 256) { - frameSpace[c++] = 0x00; - frameSpace[c++] = (blocks[i] >> 8); //block number, little endian.... - frameSpace[c++] = (blocks[i] & 0xff); + //3-byte block + if (blocks[i] >= 256) { + frameSpace[c++] = 0x00; + frameSpace[c++] = (blocks[i] >> 8); //block number, little endian.... + frameSpace[c++] = (blocks[i] & 0xff); } else { frameSpace[c++] = 0x80; frameSpace[c++] = blocks[i]; } } - - //set length - frameSpace[2] = c-2; - AddCrc(frameSpace, c-2); + + //set length + frameSpace[2] = c - 2; + AddCrc(frameSpace, c - 2); } -static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) { - - uint8_t flags = FPGA_MAJOR_MODE_ISO18092; +static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) { - if ( power ) - flags |= FPGA_HF_ISO18092_FLAG_READER; - if (highspeed) - flags |= FPGA_HF_ISO18092_FLAG_424K; + uint8_t flags = FPGA_MAJOR_MODE_ISO18092; - FpgaWriteConfWord(flags); - - uint32_t curr_transfer_time = ((MAX(felica_nexttransfertime, GetCountSspClk()) & 0xfffffff8) + 8); + if (power) + flags |= FPGA_HF_ISO18092_FLAG_READER; + if (highspeed) + flags |= FPGA_HF_ISO18092_FLAG_424K; - while (GetCountSspClk() < curr_transfer_time) {}; + FpgaWriteConfWord(flags); + + uint32_t curr_transfer_time = ((MAX(felica_nexttransfertime, GetCountSspClk()) & 0xfffffff8) + 8); + + while (GetCountSspClk() < curr_transfer_time) {}; + + felica_lasttime_prox2air_start = curr_transfer_time; - felica_lasttime_prox2air_start = curr_transfer_time; - // preamble - // sending 0x00 0x00 0x00 0x00 0x00 0x00 - uint16_t c = 0; - while (c < 6) { + // sending 0x00 0x00 0x00 0x00 0x00 0x00 + uint16_t c = 0; + while (c < 6) { - // keep tx buffer in a defined state anyway. - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - c++; - } - } - // sending sync code + // keep tx buffer in a defined state anyway. + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + c++; + } + } + // sending sync code - // sending data - c = 0; - while (c < len) { + // sending data + c = 0; + while (c < len) { - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = frame[c++]; - } - } + // Put byte into tx holding register as soon as it is ready + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = frame[c++]; + } + } -/**/ - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {}; - AT91C_BASE_SSC->SSC_THR = 0x00; //minimum delay - - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {}; - AT91C_BASE_SSC->SSC_THR = 0x00; //spin -/**/ + /**/ + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {}; + AT91C_BASE_SSC->SSC_THR = 0x00; //minimum delay - // log - LogTrace( - frame, - len, - (felica_lasttime_prox2air_start<<4) + DELAY_ARM2AIR_AS_READER, - ((felica_lasttime_prox2air_start + felica_lasttime_prox2air_start)<<4) + DELAY_ARM2AIR_AS_READER, - NULL, - true - ); - - felica_nexttransfertime = MAX(felica_nexttransfertime ,felica_lasttime_prox2air_start + FELICA_REQUEST_GUARD_TIME); + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) {}; + AT91C_BASE_SSC->SSC_THR = 0x00; //spin + /**/ + + // log + LogTrace( + frame, + len, + (felica_lasttime_prox2air_start << 4) + DELAY_ARM2AIR_AS_READER, + ((felica_lasttime_prox2air_start + felica_lasttime_prox2air_start) << 4) + DELAY_ARM2AIR_AS_READER, + NULL, + true + ); + + felica_nexttransfertime = MAX(felica_nexttransfertime, felica_lasttime_prox2air_start + FELICA_REQUEST_GUARD_TIME); } // Wait for tag reply @@ -384,227 +382,228 @@ static void TransmitFor18092_AsReader(uint8_t * frame, int len, uint32_t *timing // or return TRUE when command is captured bool WaitForFelicaReply(uint16_t maxbytes) { - uint32_t c = 0; - - // power, no modulation - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + uint32_t c = 0; - NFCFrameReset(); + // power, no modulation + FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - uint32_t timeout = felica_get_timeout(); - for(;;) { - WDT_HIT(); - - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); - ProcessNFCByte(b); - if (NFCFrame.state == STATE_FULL) { - felica_nexttransfertime = - MAX( - felica_nexttransfertime, - (GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/16 + FELICA_FRAME_DELAY_TIME - ) - ; - - LogTrace( - NFCFrame.framebytes, - NFCFrame.len, - ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER - timeout, - ((GetCountSspClk() & 0xfffffff8)<<4) - DELAY_AIR2ARM_AS_READER, - NULL, - false - ); - return true; - } else if (c++ > timeout && NFCFrame.state == STATE_UNSYNCD) { - return false; - } else if (NFCFrame.state == STATE_GET_CRC) { - Dbprintf(" Frame: "); - Dbhexdump(16, NFCFrame.framebytes, 0); - //return false; - } - } - } - return false; + FelicaFrameReset(); + + // clear RXRDY: + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + + uint32_t timeout = iso18092_get_timeout(); + for (;;) { + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); + Process18092Byte(b); + if (FelicaFrame.state == STATE_FULL) { + felica_nexttransfertime = + MAX( + felica_nexttransfertime, + (GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME + ) + ; + + LogTrace( + FelicaFrame.framebytes, + FelicaFrame.len, + ((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER - timeout, + ((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER, + NULL, + false + ); + return true; + } else if (c++ > timeout && FelicaFrame.state == STATE_UNSYNCD) { + return false; + } else if (FelicaFrame.state == STATE_GET_CRC) { + Dbprintf(" Frame: "); + Dbhexdump(16, FelicaFrame.framebytes, 0); + //return false; + } + } + } + return false; } // Set up FeliCa communication (similar to iso14443a_setup) // field is setup for "Sending as Reader" -static void felica_setup(uint8_t fpga_minor_mode) { +static void iso18092_setup(uint8_t fpga_minor_mode) { - LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + LEDsoff(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // allocate command receive buffer - BigBuf_free(); BigBuf_Clear_ext(false); - - // Initialize Demod and Uart structs - //DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - NFCInit(BigBuf_malloc(NFC_MAX_FRAME_SIZE)); + // allocate command receive buffer + BigBuf_free(); + BigBuf_Clear_ext(false); - felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; - felica_set_timeout(2120); // 106 * 20ms maximum start-up time of card - - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // Initialize Demod and Uart structs + //DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); + FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE)); - // Set up the synchronous serial port - FpgaSetupSsc(); - - // LSB transfer. Remember to set it back to MSB with - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - - init_table(CRC_FELICA); - - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode); - - //20.4 ms generate field, start sending polling command afterwars. - SpinDelay(100); + felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; + iso18092_set_timeout(2120); // 106 * 20ms maximum start-up time of card - // Start the timer - StartCountSspClk(); - - LED_D_ON(); + init_table(CRC_FELICA); + + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Set up the synchronous serial port + FpgaSetupSsc(); + + // LSB transfer. Remember to set it back to MSB with + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode); + + //20.4 ms generate field, start sending polling command afterwars. + SpinDelay(100); + + // Start the timer + StartCountSspClk(); + + LED_D_ON(); } //----------------------------------------------------------------------------- // RAW FeliCa commands. Send out commands and store answers. //----------------------------------------------------------------------------- -// arg0 FeliCa flags -// arg1 len of commandbytes -// d.asBytes command bytes to send -void felica_sendraw(UsbCommand *c) { +// arg0 FeliCa flags +// arg1 len of commandbytes +// d.asBytes command bytes to send +void felica_sendraw(PacketCommandNG *c) { - if (MF_DBGLEVEL > 3) Dbprintf("FeliCa_sendraw Enter"); + if (DBGLEVEL > 3) Dbprintf("FeliCa_sendraw Enter"); - felica_command_t param = c->arg[0]; - size_t len = c->arg[1] & 0xffff; - uint8_t *cmd = c->d.asBytes; - uint32_t arg0 = 0; - - felica_card_select_t card; - - if ((param & FELICA_CONNECT)) - clear_trace(); + felica_command_t param = c->oldarg[0]; + size_t len = c->oldarg[1] & 0xffff; + uint8_t *cmd = c->data.asBytes; + uint32_t arg0; - set_tracing(true); + felica_card_select_t card; - if ((param & FELICA_CONNECT)) { - felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + if ((param & FELICA_CONNECT)) + clear_trace(); - // notify client selecting status. - // if failed selecting, turn off antenna and quite. - if( !(param & FELICA_NO_SELECT) ) { - arg0 = felica_select_card(&card); - cmd_send(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t)); - if ( arg0 > 0 ) - goto OUT; - } - } - - if ((param & FELICA_RAW)) { - - // 2 sync, 1 len, 2crc == 5 - uint8_t *buf = BigBuf_malloc(len+5); - // add sync bits - buf[0] = 0xb2; - buf[1] = 0x4d; - buf[2] = len; - - // copy command - memcpy(buf+2, cmd, len); - - if ((param & FELICA_APPEND_CRC)) { - // Don't append crc on empty bytearray... - if ( len > 0 ) { - AddCrc(buf, len); - len += 2; - } - } + set_tracing(true); - TransmitFor18092_AsReader(buf, buf[2]+4, NULL, 1, 0); - arg0 = !WaitForFelicaReply(1024); - cmd_send(CMD_ACK, arg0, 0, 0, NFCFrame.framebytes+2, NFCFrame.len-2); - } + if ((param & FELICA_CONNECT)) { + iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - if ((param & FELICA_NO_DISCONNECT)) - return; + // notify client selecting status. + // if failed selecting, turn off antenna and quite. + if (!(param & FELICA_NO_SELECT)) { + arg0 = felica_select_card(&card); + reply_old(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t)); + if (arg0 > 0) + goto OUT; + } + } -OUT: - switch_off(); - - //Resetting Frame mode (First set in fpgaloader.c) + if ((param & FELICA_RAW)) { + + // 2 sync, 1 len, 2crc == 5 + uint8_t *buf = BigBuf_malloc(len + 5); + // add sync bits + buf[0] = 0xb2; + buf[1] = 0x4d; + buf[2] = len; + + // copy command + memcpy(buf + 2, cmd, len); + + if ((param & FELICA_APPEND_CRC)) { + // Don't append crc on empty bytearray... + if (len > 0) { + AddCrc(buf, len); + } + } + + TransmitFor18092_AsReader(buf, buf[2] + 4, NULL, 1, 0); + arg0 = !WaitForFelicaReply(1024); + reply_old(CMD_ACK, arg0, 0, 0, FelicaFrame.framebytes + 2, FelicaFrame.len - 2); + } + + if ((param & FELICA_NO_DISCONNECT)) + return; + +OUT: + switch_off(); + + //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); - - if (MF_DBGLEVEL > 3) Dbprintf("FeliCa_sendraw Exit"); + + if (DBGLEVEL > 3) Dbprintf("FeliCa_sendraw Exit"); } void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { - + int remFrames = (samplesToSkip) ? samplesToSkip : 0; - Dbprintf("Snoop FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); - - felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD); + Dbprintf("Sniff FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); - //the frame bits are slow enough. + iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD); + + //the frame bits are slow enough. int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory - int numbts = 0; + int numbts = 0; uint8_t *dest = (uint8_t *)BigBuf_get_addr(); - uint8_t *destend = dest + n-2; + uint8_t *destend = dest + n - 2; uint32_t endframe = GetCountSspClk(); while (dest <= destend) { WDT_HIT(); - if( BUTTON_PRESS()) break; - + if (BUTTON_PRESS()) break; + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); - ProcessNFCByte(dist); - - //to be sure we are in frame - if (NFCFrame.state == STATE_GET_LENGTH) { - //length is after 48 (PRE)+16 (SYNC) - 64 ticks +maybe offset? not 100% - uint16_t distance = GetCountSspClk() - endframe - 64 + (NFCFrame.byte_offset > 0 ? (8-NFCFrame.byte_offset) : 0); + Process18092Byte(dist); + + //to be sure we are in frame + if (FelicaFrame.state == STATE_GET_LENGTH) { + //length is after 48 (PRE)+16 (SYNC) - 64 ticks +maybe offset? not 100% + uint16_t distance = GetCountSspClk() - endframe - 64 + (FelicaFrame.byte_offset > 0 ? (8 - FelicaFrame.byte_offset) : 0); *dest = distance >> 8; dest++; *dest = (distance & 0xff); dest++; } - //crc NOT checked - if (NFCFrame.state == STATE_FULL) { + //crc NOT checked + if (FelicaFrame.state == STATE_FULL) { endframe = GetCountSspClk(); - //*dest = NFCFrame.crc_ok; //kind of wasteful + //*dest = FelicaFrame.crc_ok; //kind of wasteful dest++; - for(int i=0; i < NFCFrame.len; i++) { - *dest = NFCFrame.framebytes[i]; + for (int i = 0; i < FelicaFrame.len; i++) { + *dest = FelicaFrame.framebytes[i]; dest++; - if (dest >= destend ) break; + if (dest >= destend) break; } remFrames--; if (remFrames <= 0) break; - if (dest >= destend ) break; - - numbts += NFCFrame.len; - - NFCFrameReset(); + if (dest >= destend) break; + + numbts += FelicaFrame.len; + + FelicaFrameReset(); } } } - switch_off(); - + switch_off(); + //reset framing AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); set_tracelen(numbts); Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen()); - cmd_send(CMD_ACK,1, numbts,0,0,0); + reply_old(CMD_ACK, 1, numbts, 0, 0, 0); } #define R_POLL0_LEN 0x16 @@ -612,30 +611,30 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { #define R_READBLK_LEN 0x21 //simulate NFC Tag3 card - for now only poll response works // second half (4 bytes) of NDEF2 goes into nfcid2_0, first into nfcid2_1 -void felica_sim_lite(uint64_t nfcid) { +void felica_sim_lite(uint64_t uid) { int i, curlen = 0; uint8_t *curresp = 0; - uint8_t ndef[8]; - num_to_bytes(nfcid, 8, ndef); + uint8_t ndef[8]; + num_to_bytes(uid, 8, ndef); - //prepare our 3 responses... - uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2,0x4d,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f}; - uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2,0x4d,0x14,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00, 0x88,0xb4,0xb3,0x7f}; - uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2,0x4d,0x1d,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x04,0x01,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0xcb,0x6e}; - - //NFC tag 3/ ISo technically. Many overlapping standards - DbpString("Felica Lite-S sim start"); + //prepare our 3 responses... + uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2, 0x4d, 0x12, FELICA_POLL_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f}; + uint8_t resp_poll1[R_POLL1_LEN] = { 0xb2, 0x4d, 0x14, FELICA_POLL_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0x88, 0xb4, 0xb3, 0x7f}; + uint8_t resp_readblk[R_READBLK_LEN] = { 0xb2, 0x4d, 0x1d, FELICA_RDBLK_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x04, 0x01, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x23, 0xcb, 0x6e}; + + //NFC tag 3/ ISo technically. Many overlapping standards + DbpString("Felica Lite-S sim start"); Dbprintf("NDEF2 UID: %02x %02x %02x %02x %02x %02x %02x %02x", - ndef[0], ndef[1], ndef[2], ndef[3], ndef[4], ndef[5], ndef[6], ndef[7] - ); - + ndef[0], ndef[1], ndef[2], ndef[3], ndef[4], ndef[5], ndef[6], ndef[7] + ); + //fill in blanks - for( i=0; i<8; i++) { - resp_poll0[i+4] = ndef[i]; - resp_poll1[i+4] = ndef[i]; - resp_readblk[i+4] = ndef[i]; + for (i = 0; i < 8; i++) { + resp_poll0[i + 4] = ndef[i]; + resp_poll1[i + 4] = ndef[i]; + resp_readblk[i + 4] = ndef[i]; } //calculate and set CRC @@ -643,42 +642,42 @@ void felica_sim_lite(uint64_t nfcid) { AddCrc(resp_poll1, resp_poll1[2]); AddCrc(resp_readblk, resp_readblk[2]); - felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD); + iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD); - bool listenmode = true; - //uint32_t frtm = GetCountSspClk(); - for(;;) { - if( BUTTON_PRESS()) break; + bool listenmode = true; + //uint32_t frtm = GetCountSspClk(); + for (;;) { + if (BUTTON_PRESS()) break; WDT_HIT(); if (listenmode) { //waiting for request... if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); - //frtm = GetCountSspClk(); - ProcessNFCByte(dist); - - if (NFCFrame.state == STATE_FULL) { + uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); + //frtm = GetCountSspClk(); + Process18092Byte(dist); - if (NFCFrame.crc_ok) { - - if (NFCFrame.framebytes[2] == 6 && NFCFrame.framebytes[3] == 0) { + if (FelicaFrame.state == STATE_FULL) { - //polling... there are two types of polling we answer to - if (NFCFrame.framebytes[6] == 0) { - curresp = resp_poll0; - curlen = R_POLL0_LEN; - listenmode = false; - } - if (NFCFrame.framebytes[6] == 1) { - curresp = resp_poll1; - curlen = R_POLL1_LEN; - listenmode = true; - } + if (FelicaFrame.crc_ok) { + + if (FelicaFrame.framebytes[2] == 6 && FelicaFrame.framebytes[3] == 0) { + + //polling... there are two types of polling we answer to + if (FelicaFrame.framebytes[6] == 0) { + curresp = resp_poll0; + curlen = R_POLL0_LEN; + listenmode = false; + } + if (FelicaFrame.framebytes[6] == 1) { + curresp = resp_poll1; + curlen = R_POLL1_LEN; + listenmode = true; + } } - - if (NFCFrame.framebytes[2] > 5 && NFCFrame.framebytes[3] == 0x06) { + + if (FelicaFrame.framebytes[2] > 5 && FelicaFrame.framebytes[3] == 0x06) { //we should rebuild it depending on page size, but... //Let's see first curresp = resp_readblk; @@ -686,33 +685,33 @@ void felica_sim_lite(uint64_t nfcid) { listenmode = false; } //clear frame - NFCFrameReset(); + FelicaFrameReset(); } else { //frame invalid, clear it out to allow for the next one - NFCFrameReset(); - } - } - } - } - if (!listenmode) { - //trying to answer... here to start answering immediately. - //this one is a bit finicky. Seems that being a bit late is better than earlier - //TransmitFor18092_AsReader(curresp, curlen, frtm+512, 0, 0); - TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0); + FelicaFrameReset(); + } + } + } + } + if (!listenmode) { + //trying to answer... here to start answering immediately. + //this one is a bit finicky. Seems that being a bit late is better than earlier + //TransmitFor18092_AsReader(curresp, curlen, frtm+512, 0, 0); + TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0); - //switch back - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); + //switch back + FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); - NFCFrameReset(); - listenmode = true; - curlen = 0; - curresp = NULL; + FelicaFrameReset(); + listenmode = true; + curlen = 0; + curresp = NULL; } } - + switch_off(); - //reset framing + //reset framing AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); DbpString("Felica Lite-S sim end"); @@ -720,80 +719,80 @@ void felica_sim_lite(uint64_t nfcid) { void felica_dump_lite_s() { - uint8_t ndef[8]; - uint8_t poll[10] = { 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21}; - uint16_t liteblks[28] = {0x00, 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x90,0x91,0x92,0xa0}; - - // setup device. - felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - - uint8_t blknum; - bool isOK = false; - uint16_t cnt = 0, cntfails = 0; - uint8_t *dest = BigBuf_get_addr(); + uint8_t ndef[8]; + uint8_t poll[10] = { 0xb2, 0x4d, 0x06, FELICA_POLL_REQ, 0xff, 0xff, 0x00, 0x00, 0x09, 0x21}; + uint16_t liteblks[28] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x90, 0x91, 0x92, 0xa0}; - while (!BUTTON_PRESS() && !usb_poll_validate_length()) { - - WDT_HIT(); - - // polling? - //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); - TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); - - if (WaitForFelicaReply(512) && NFCFrame.framebytes[3] == FELICA_POLL_ACK) { - - // copy 8bytes to ndef. - memcpy(ndef, NFCFrame.framebytes + 4, 8); - // for (c=0; c < 8; c++) - // ndef[c] = NFCFrame.framebytes[c+4]; - - for (blknum=0; blknum < sizeof(liteblks); ) { + // setup device. + iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); - // block to read. - BuildFliteRdblk(ndef, 1, &liteblks[blknum]); - - //TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, GetCountSspClk()+512, 1, 0); - TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, NULL, 1, 0); - - // read block - if (WaitForFelicaReply(1024) && NFCFrame.framebytes[3] == FELICA_RDBLK_ACK) { + uint8_t blknum; + bool isOK = false; + uint16_t cnt = 0, cntfails = 0; + uint8_t *dest = BigBuf_get_addr(); - dest[cnt++] = liteblks[blknum]; + while (!BUTTON_PRESS() && !data_available()) { - uint8_t *fb = NFCFrame.framebytes; - dest[cnt++] = fb[12]; - dest[cnt++] = fb[13]; + WDT_HIT(); - //memcpy(dest+cnt, NFCFrame.framebytes + 15, 16); - //cnt += 16; - for(uint8_t j=0; j < 16; j++) - dest[cnt++] = fb[15+j]; - - blknum++; - cntfails = 0; - - // // print raw log. - // Dbprintf("LEN %u | Dump bytes count %u ", NFCFrame.len, cnt); - Dbhexdump(NFCFrame.len, NFCFrame.framebytes+15, 0); - } else { - cntfails++; - if (cntfails > 12) { - blknum++; - cntfails = 0; - } - } - } - isOK = true; - break; - } - } - - switch_off(); + // polling? + //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); + TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); - //Resetting Frame mode (First set in fpgaloader.c) + if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) { + + // copy 8bytes to ndef. + memcpy(ndef, FelicaFrame.framebytes + 4, 8); + // for (c=0; c < 8; c++) + // ndef[c] = FelicaFrame.framebytes[c+4]; + + for (blknum = 0; blknum < sizeof(liteblks);) { + + // block to read. + BuildFliteRdblk(ndef, 1, &liteblks[blknum]); + + //TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, GetCountSspClk()+512, 1, 0); + TransmitFor18092_AsReader(frameSpace, frameSpace[2] + 4, NULL, 1, 0); + + // read block + if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) { + + dest[cnt++] = liteblks[blknum]; + + uint8_t *fb = FelicaFrame.framebytes; + dest[cnt++] = fb[12]; + dest[cnt++] = fb[13]; + + //memcpy(dest+cnt, FelicaFrame.framebytes + 15, 16); + //cnt += 16; + for (uint8_t j = 0; j < 16; j++) + dest[cnt++] = fb[15 + j]; + + blknum++; + cntfails = 0; + + // // print raw log. + // Dbprintf("LEN %u | Dump bytes count %u ", FelicaFrame.len, cnt); + Dbhexdump(FelicaFrame.len, FelicaFrame.framebytes + 15, 0); + } else { + cntfails++; + if (cntfails > 12) { + blknum++; + cntfails = 0; + } + } + } + isOK = true; + break; + } + } + + switch_off(); + + //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); - - //setting tracelen - important! it was set by buffer overflow before + + //setting tracelen - important! it was set by buffer overflow before set_tracelen(cnt); - cmd_send(CMD_ACK, isOK, cnt, 0, 0, 0); + reply_old(CMD_ACK, isOK, cnt, 0, 0, 0); } diff --git a/armsrc/flashmem.c b/armsrc/flashmem.c index 7c5beb47a..4584d41b2 100644 --- a/armsrc/flashmem.c +++ b/armsrc/flashmem.c @@ -1,88 +1,140 @@ #include "flashmem.h" /* here: use NCPS2 @ PA10: */ -#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4) - -/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */ -#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110 -#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101 -#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011 -#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111 - -// TODO -#if (SPI_CSR_NUM == 0) -#define SPI_MR_PCS PCS_0 -#elif (SPI_CSR_NUM == 1) -#define SPI_MR_PCS PCS_1 -#elif (SPI_CSR_NUM == 2) -#define SPI_MR_PCS PCS_2 -#elif (SPI_CSR_NUM == 3) -#define SPI_MR_PCS PCS_3 -#else -#error "SPI_CSR_NUM invalid" -// not realy - when using an external address decoder... -// but this code takes over the complete SPI-interace anyway -#endif +#define SPI_CSR_NUM 2 +#define SPI_PCS(npcs) ((~(1 << (npcs)) & 0xF) << 16) +/// Calculates the value of the CSR SCBR field given the baudrate and MCK. +#define SPI_SCBR(baudrate, masterClock) ((uint32_t) ((masterClock) / (baudrate)) << 8) +/// Calculates the value of the CSR DLYBS field given the desired delay (in ns) +#define SPI_DLYBS(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 1000) << 16) +/// Calculates the value of the CSR DLYBCT field given the desired delay (in ns) +#define SPI_DLYBCT(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 32000) << 24) -/* - ¶ÁȡָÁ¿ÉÒÔ´ÓÒ»¸öλÖÿªÊ¼³ÖÐøµÄ¶Á£¬×î¶àÄܽ«Õû¿éоƬ¶ÁÈ¡Íê - ҳдָÁÿ´ÎдÈëΪ1-256×Ö½Ú£¬µ«ÊDz»ÄÜ¿çÔ½256×ֽڱ߽ç - ²Á³ýÖ¸Á²Á³ýÖ¸Áîºó±ØÐ뽫CSÀ­¸ß£¬·ñÔò²»»áÖ´ÐÐ -*/ +uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD; -void FlashSetup(void) { - // PA1 -> SPI_NCS3 chip select (MEM) - // PA10 -> SPI_NCS2 chip select (LCD) - // PA11 -> SPI_NCS0 chip select (FPGA) - // PA12 -> SPI_MISO Master-In Slave-Out - // PA13 -> SPI_MOSI Master-Out Slave-In - // PA14 -> SPI_SPCK Serial Clock +void FlashmemSetSpiBaudrate(uint32_t baudrate) { + FLASHMEM_SPIBAUDRATE = baudrate; + Dbprintf("Spi Baudrate : %dMhz", FLASHMEM_SPIBAUDRATE / 1000000); +} - // Disable PIO control of the following pins, allows use by the SPI peripheral - AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2); +// initialize +bool FlashInit() { + FlashSetup(FLASHMEM_SPIBAUDRATE); - // Pull-up Enable - AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2); + StartTicks(); - // Peripheral A - AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK); + if (Flash_CheckBusy(BUSY_TIMEOUT)) { + StopTicks(); + return false; + } - // Peripheral B - AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2; + return true; +} - //enable the SPI Peripheral clock - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI); +void FlashSetup(uint32_t baudrate) { + //WDT_DISABLE + AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS; - // Enable SPI - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; + // PA10 -> SPI_NCS2 chip select (FLASHMEM) + // PA11 -> SPI_NCS0 chip select (FPGA) + // PA12 -> SPI_MISO Master-In Slave-Out + // PA13 -> SPI_MOSI Master-Out Slave-In + // PA14 -> SPI_SPCK Serial Clock - // NPCS2 Mode 0 - AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (0xB << 16) | // Peripheral Chip Select (selects 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 + // Disable PIO control of the following pins, allows use by the SPI peripheral + AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2); - // 8 bit - AT91C_BASE_SPI->SPI_CSR[2] = - ( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 0 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 0 << 4) | // Bits per Transfer (8 bits) - ( 1 << 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 + // Pull-up Enable + AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2); - // read first, empty buffer - if (AT91C_BASE_SPI->SPI_RDR == 0) {}; + // Peripheral A + AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK); + + // Peripheral B + AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2; + + //enable the SPI Peripheral clock + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI); + + + //reset spi needs double SWRST, see atmel's errata on this case + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; + + // Enable SPI + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; + + // NPCS2 Mode 0 + AT91C_BASE_SPI->SPI_MR = + (0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT: + // If DLYBCS is less than or equal to six, six MCK periods + // will be inserted by default. + SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10) + (0 << 7) | // Disable LLB (1=MOSI2MISO test mode) + (1 << 4) | // Disable ModeFault Protection + (0 << 3) | // makes spi operate at MCK (1 is MCK/2) + (0 << 2) | // Chip selects connected directly to peripheral + AT91C_SPI_PS_FIXED | // Fixed Peripheral Select + AT91C_SPI_MSTR; // Master Mode + + uint8_t csaat = 1; + uint32_t dlybct = 0; + uint8_t ncpha = 1; + uint8_t cpol = 0; + if (baudrate > FLASH_MINFAST) { + baudrate = FLASH_FASTBAUD; + //csaat = 0; + dlybct = 1500; + ncpha = 0; + cpol = 0; + } + + AT91C_BASE_SPI->SPI_CSR[2] = + SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods) + SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock + SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection + AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits) + //AT91C_SPI_CSAAT | // Chip Select inactive after transfer + // 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1 + // If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on + // the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been + // transferred in the shifter. This can imply for example, that the second data is sent twice. + // COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay + (csaat << 3) | + /* Spi modes: + Mode CPOL CPHA NCPHA + 0 0 0 1 clock normally low read on rising edge + 1 0 1 0 clock normally low read on falling edge + 2 1 0 1 clock normally high read on falling edge + 3 1 1 0 clock normally high read on rising edge + However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI + master mode the ATSAM7S512/256/128/64/321/32 does not sample the data + (MISO) on the opposite edge where data clocks out (MOSI) but the same + edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3 + shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and + that the data changes sometime after the rising edge (about 2 ns). To + be consistent with normal SPI operation, it is probably safe to say + that the data changes on the falling edge and should be sampled on the + rising edge. Therefore, it appears that NCPHA should be treated the + same as CPHA. Thus: + Mode CPOL CPHA NCPHA + 0 0 0 0 clock normally low read on rising edge + 1 0 1 1 clock normally low read on falling edge + 2 1 0 0 clock normally high read on falling edge + 3 1 1 1 clock normally high read on rising edge + Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur. + */ + (ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge + (cpol << 0); // Clock Polarity inactive state is logic 0 + + // read first, empty buffer + if (AT91C_BASE_SPI->SPI_RDR == 0) {}; } void FlashStop(void) { - //* Reset all the Chip Select register + //Bof + //* Reset all the Chip Select register AT91C_BASE_SPI->SPI_CSR[0] = 0; AT91C_BASE_SPI->SPI_CSR[1] = 0; AT91C_BASE_SPI->SPI_CSR[2] = 0; @@ -93,252 +145,348 @@ void FlashStop(void) { // Disable all interrupts AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF; - - // SPI disable - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; - if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashStop"); - - StopTicks(); + // SPI disable + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; + + if (DBGLEVEL > 3) Dbprintf("FlashStop"); + + StopTicks(); } -// send one byte over SPI -uint16_t FlashSendByte(uint32_t data) { - uint16_t incoming = 0; +// send one byte over SPI +uint16_t FlashSendByte(uint32_t data) { - WDT_HIT(); + // wait until SPI is ready for transfer + //if you are checking for incoming data returned then the TXEMPTY flag is redundant + //while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {}; - // wait until SPI is ready for transfer - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {}; + // send the data + AT91C_BASE_SPI->SPI_TDR = data; - // send the data - AT91C_BASE_SPI->SPI_TDR = data; + //while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){}; - // wait recive transfer is complete - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) - WDT_HIT(); + // wait recive transfer is complete + while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {}; - // reading incoming data - incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF); - - return incoming; + // reading incoming data + return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF); } -// send last byte over SPI +// send last byte over SPI uint16_t FlashSendLastByte(uint32_t data) { - return FlashSendByte(data | AT91C_SPI_LASTXFER); + return FlashSendByte(data | AT91C_SPI_LASTXFER); } -// read state register 1 +// read state register 1 uint8_t Flash_ReadStat1(void) { - FlashSendByte(READSTAT1); - uint8_t stat1 = FlashSendLastByte(0xFF); -// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat1 [%02x]", stat1); - return stat1; + FlashSendByte(READSTAT1); + return FlashSendLastByte(0xFF); } -// read state register 2 -uint8_t Flash_ReadStat2(void) { - FlashSendByte(READSTAT2); - uint8_t stat2 = FlashSendLastByte(0xFF); -// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat2 [%02x]", stat2); - return stat2; -} +bool Flash_CheckBusy(uint32_t timeout) { + WaitUS(WINBOND_WRITE_DELAY); + StartCountUS(); + uint32_t _time = GetCountUS(); -// determine whether FLASHMEM is busy -bool Flash_CheckBusy(uint16_t times) { - bool ret = (Flash_ReadStat1() & BUSY); + if (DBGLEVEL > 3) Dbprintf("Checkbusy in..."); - if (!ret || !times || !(times--)) - return ret; + do { + if (!(Flash_ReadStat1() & BUSY)) { + return false; + } + } while ((GetCountUS() - _time) < timeout); - while (times) { - WDT_HIT(); - SpinDelay(1); - ret = (Flash_ReadStat1() & BUSY); - if (!ret) - break; - times--; - } - return ret; + if (timeout <= (GetCountUS() - _time)) { + return true; + } + + return false; } // read ID out uint8_t Flash_ReadID(void) { - if (Flash_CheckBusy(100)) return 0; + if (Flash_CheckBusy(BUSY_TIMEOUT)) return 0; - // Manufacture ID / device ID - FlashSendByte(ID); - FlashSendByte(0x00); - FlashSendByte(0x00); - FlashSendByte(0x00); + // Manufacture ID / device ID + FlashSendByte(ID); + FlashSendByte(0x00); + FlashSendByte(0x00); + FlashSendByte(0x00); uint8_t man_id = FlashSendByte(0xFF); - uint8_t dev_id = FlashSendLastByte(0xFF); + uint8_t dev_id = FlashSendLastByte(0xFF); - if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id); - - if ( (man_id == WINBOND_MANID ) && (dev_id == WINBOND_DEVID) ) - return dev_id; + if (DBGLEVEL > 3) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id); - return 0; + if ((man_id == WINBOND_MANID) && (dev_id == WINBOND_DEVID)) + return dev_id; + + return 0; } // read unique id for chip. void Flash_UniqueID(uint8_t *uid) { - if (Flash_CheckBusy(100)) return; + if (Flash_CheckBusy(BUSY_TIMEOUT)) return; - // reading unique serial number - FlashSendByte(UNIQUE_ID); - FlashSendByte(0xFF); - FlashSendByte(0xFF); - FlashSendByte(0xFF); - FlashSendByte(0xFF); + // reading unique serial number + FlashSendByte(UNIQUE_ID); + FlashSendByte(0xFF); + FlashSendByte(0xFF); + FlashSendByte(0xFF); + FlashSendByte(0xFF); - uid[7] = FlashSendByte(0xFF); - uid[6] = FlashSendByte(0xFF); - uid[5] = FlashSendByte(0xFF); - uid[4] = FlashSendByte(0xFF); + uid[7] = FlashSendByte(0xFF); + uid[6] = FlashSendByte(0xFF); + uid[5] = FlashSendByte(0xFF); + uid[4] = FlashSendByte(0xFF); uid[3] = FlashSendByte(0xFF); - uid[2] = FlashSendByte(0xFF); - uid[1] = FlashSendByte(0xFF); - uid[0] = FlashSendLastByte(0xFF); + uid[2] = FlashSendByte(0xFF); + uid[1] = FlashSendByte(0xFF); + uid[0] = FlashSendLastByte(0xFF); } uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) { - - if (!FlashInit()) return 0; - - Flash_ReadStat1(); - - // length should never be zero - if (!len || Flash_CheckBusy(100)) return 0; - FlashSendByte(READDATA); - FlashSendByte((address >> 16) & 0xFF); - FlashSendByte((address >> 8) & 0xFF); - FlashSendByte((address >> 0) & 0xFF); + if (!FlashInit()) return 0; - uint16_t i = 0; - for (; i < (len - 1); i++) - out[i] = FlashSendByte(0xFF); + // length should never be zero + if (!len || Flash_CheckBusy(BUSY_TIMEOUT)) return 0; - out[i] = FlashSendLastByte(0xFF); - - FlashStop(); - return len; + uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA; + + FlashSendByte(cmd); + Flash_TransferAdresse(address); + + if (FASTFLASH) { + FlashSendByte(DUMMYBYTE); + } + + uint16_t i = 0; + for (; i < (len - 1); i++) + out[i] = FlashSendByte(0xFF); + + out[i] = FlashSendLastByte(0xFF); + FlashStop(); + return len; } -// Write data can only program one page. A page has 256 bytes. +void Flash_TransferAdresse(uint32_t address) { + FlashSendByte((address >> 16) & 0xFF); + FlashSendByte((address >> 8) & 0xFF); + FlashSendByte((address >> 0) & 0xFF); +} + +/* This ensure we can ReadData without having to cycle through initialization everytime */ +uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) { + + // length should never be zero + if (!len) return 0; + + uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA; + + FlashSendByte(cmd); + Flash_TransferAdresse(address); + + if (FASTFLASH) { + FlashSendByte(DUMMYBYTE); + } + + uint16_t i = 0; + for (; i < (len - 1); i++) + out[i] = FlashSendByte(0xFF); + + out[i] = FlashSendLastByte(0xFF); + return len; +} + + +//////////////////////////////////////// +// Write data can only program one page. A page has 256 bytes. // if len > 256, it might wrap around and overwrite pos 0. uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) { - // length should never be zero - if (!len) - return 0; - - // Max 256 bytes write - if (((address & 0xFF) + len) > 256) { - Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF)+len, len ); - return 0; - } - - // out-of-range - if ( (( address >> 16 ) & 0xFF ) > MAX_BLOCKS) { - Dbprintf("Flash_WriteData, block out-of-range"); - return 0; - } + // length should never be zero + if (!len) + return 0; - if (!FlashInit()) { - if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail"); - return 0; - } - - Flash_ReadStat1(); + // Max 256 bytes write + if (((address & 0xFF) + len) > 256) { + Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len); + return 0; + } - Flash_WriteEnable(); - - FlashSendByte(PAGEPROG); - FlashSendByte((address >> 16) & 0xFF); - FlashSendByte((address >> 8) & 0xFF); - FlashSendByte((address >> 0) & 0xFF); + // out-of-range + if (((address >> 16) & 0xFF) > MAX_BLOCKS) { + Dbprintf("Flash_WriteData, block out-of-range"); + return 0; + } - uint16_t i = 0; - for (; i < (len - 1); i++) - FlashSendByte(in[i]); + if (!FlashInit()) { + if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail"); + return 0; + } - FlashSendLastByte(in[i]); + Flash_CheckBusy(BUSY_TIMEOUT); - FlashStop(); - return len; + Flash_WriteEnable(); + + FlashSendByte(PAGEPROG); + FlashSendByte((address >> 16) & 0xFF); + FlashSendByte((address >> 8) & 0xFF); + FlashSendByte((address >> 0) & 0xFF); + + uint16_t i = 0; + for (; i < (len - 1); i++) + FlashSendByte(in[i]); + + FlashSendLastByte(in[i]); + + FlashStop(); + return len; } -bool Flash_WipeMemoryPage(uint8_t page) { - if (!FlashInit()) { - if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail"); - return false; - } - Flash_ReadStat1(); - - // Each block is 64Kb. One block erase takes 1s ( 1000ms ) - Flash_WriteEnable(); Flash_Erase64k(page); Flash_CheckBusy(1000); - FlashStop(); - return true; +// length should never be zero +// Max 256 bytes write +// out-of-range +uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len) { + + if (!len) + return 0; + + if (((address & 0xFF) + len) > 256) { + Dbprintf("Flash_WriteDataCont 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len); + return 0; + } + + if (((address >> 16) & 0xFF) > MAX_BLOCKS) { + Dbprintf("Flash_WriteDataCont, block out-of-range"); + return 0; + } + + FlashSendByte(PAGEPROG); + FlashSendByte((address >> 16) & 0xFF); + FlashSendByte((address >> 8) & 0xFF); + FlashSendByte((address >> 0) & 0xFF); + + uint16_t i = 0; + for (; i < (len - 1); i++) + FlashSendByte(in[i]); + + FlashSendLastByte(in[i]); + return len; +} + +// assumes valid start 256 based 00 address +// +uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len) { + + bool isok; + uint16_t res, bytes_sent = 0, bytes_remaining = len; + uint8_t buf[FLASH_MEM_BLOCK_SIZE]; + while (bytes_remaining > 0) { + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + + uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + memcpy(buf, in + bytes_sent, bytes_in_packet); + + res = Flash_WriteDataCont(address + bytes_sent, buf, bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + isok = (res == bytes_in_packet); + + if (!isok) + goto out; + } + +out: + FlashStop(); + return len; +} + + +bool Flash_WipeMemoryPage(uint8_t page) { + if (!FlashInit()) { + if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail"); + return false; + } + Flash_ReadStat1(); + + // Each block is 64Kb. One block erase takes 1s ( 1000ms ) + Flash_WriteEnable(); + Flash_Erase64k(page); + Flash_CheckBusy(BUSY_TIMEOUT); + + FlashStop(); + return true; } // Wipes flash memory completely, fills with 0xFF bool Flash_WipeMemory() { - if (!FlashInit()) { - if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail"); - return false; - } - Flash_ReadStat1(); - - // Each block is 64Kb. Four blocks - // one block erase takes 1s ( 1000ms ) - Flash_WriteEnable(); Flash_Erase64k(0); Flash_CheckBusy(1000); - Flash_WriteEnable(); Flash_Erase64k(1); Flash_CheckBusy(1000); - Flash_WriteEnable(); Flash_Erase64k(2); Flash_CheckBusy(1000); - Flash_WriteEnable(); Flash_Erase64k(3); Flash_CheckBusy(1000); - - FlashStop(); - return true; + if (!FlashInit()) { + if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail"); + return false; + } + Flash_ReadStat1(); + + // Each block is 64Kb. Four blocks + // one block erase takes 1s ( 1000ms ) + Flash_WriteEnable(); + Flash_Erase64k(0); + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase64k(1); + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase64k(2); + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase64k(3); + Flash_CheckBusy(BUSY_TIMEOUT); + + FlashStop(); + return true; } -// enable the flash write +// enable the flash write void Flash_WriteEnable() { - FlashSendLastByte(WRITEENABLE); - if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash Write enabled"); + FlashSendLastByte(WRITEENABLE); + if (DBGLEVEL > 3) Dbprintf("Flash Write enabled"); } -// erase 4K at one time +// erase 4K at one time // execution time: 0.8ms / 800us bool Flash_Erase4k(uint8_t block, uint8_t sector) { - if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false; + if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false; - FlashSendByte(SECTORERASE); - FlashSendByte(block); - FlashSendByte(sector << 4); - FlashSendLastByte(00); - return true; + FlashSendByte(SECTORERASE); + FlashSendByte(block); + FlashSendByte(sector << 4); + FlashSendLastByte(00); + return true; } /* -// erase 32K at one time +// erase 32K at one time // execution time: 0,3s / 300ms bool Flash_Erase32k(uint32_t address) { - if (address & (32*1024 - 1)) { - if ( MF_DBGLEVEL > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096"); - return false; - } - FlashSendByte(BLOCK32ERASE); - FlashSendByte((address >> 16) & 0xFF); - FlashSendByte((address >> 8) & 0xFF); - FlashSendLastByte((address >> 0) & 0xFF); - return true; + if (address & (32*1024 - 1)) { + if ( DBGLEVEL > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096"); + return false; + } + FlashSendByte(BLOCK32ERASE); + FlashSendByte((address >> 16) & 0xFF); + FlashSendByte((address >> 8) & 0xFF); + FlashSendLastByte((address >> 0) & 0xFF); + return true; } */ @@ -351,67 +499,90 @@ bool Flash_Erase32k(uint32_t address) { // 0x02 00 00 -- 0x 02 FF FF == block 2 // 0x03 00 00 -- 0x 03 FF FF == block 3 bool Flash_Erase64k(uint8_t block) { - - if (block > MAX_BLOCKS) return false; - - FlashSendByte(BLOCK64ERASE); - FlashSendByte(block); - FlashSendByte(0x00); - FlashSendLastByte(0x00); - return true; + + if (block > MAX_BLOCKS) return false; + + FlashSendByte(BLOCK64ERASE); + FlashSendByte(block); + FlashSendByte(0x00); + FlashSendLastByte(0x00); + return true; } -// Erase chip +/* +// Erase chip void Flash_EraseChip(void) { - FlashSendLastByte(CHIPERASE); -} - -// initialize -bool FlashInit(void) { - FlashSetup(); - - StartTicks(); - - if (Flash_CheckBusy(100)) { - StopTicks(); - return false; - } - - if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashInit OK"); - return true; + FlashSendLastByte(CHIPERASE); } +*/ void Flashmem_print_status(void) { - DbpString("Flash memory"); + DbpString(_BLUE_("Flash memory")); + Dbprintf(" Baudrate................" _GREEN_("%d MHz"), FLASHMEM_SPIBAUDRATE / 1000000); + + if (!FlashInit()) { + DbpString(" Init...................." _RED_("FAILED")); + return; + } + DbpString(" Init...................." _GREEN_("OK")); + + uint8_t dev_id = Flash_ReadID(); + switch (dev_id) { + case 0x11 : + DbpString(" Memory size............." _YELLOW_("2 mbits / 256 kb")); + break; + case 0x10 : + DbpString(" Memory size..... ......." _YELLOW_("1 mbits / 128 kb")); + break; + case 0x05 : + DbpString(" Memory size............." _YELLOW_("512 kbits / 64 kb")); + break; + default : + DbpString(" Device ID..............." _YELLOW_(" --> Unknown <--")); + break; + } + + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + Flash_UniqueID(uid); + Dbprintf(" Unique ID...............0x%02X%02X%02X%02X%02X%02X%02X%02X", + uid[7], uid[6], uid[5], uid[4], + uid[3], uid[2], uid[1], uid[0] + ); + + FlashStop(); +} + +void Flashmem_print_info(void) { + if (!FlashInit()) return; + + DbpString(_BLUE_("Flash memory dictionary loaded")); + + // load dictionary offsets. + uint8_t keysum[2]; + uint16_t num; + + uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET, keysum, 2); + if (isok == 2) { + num = ((keysum[1] << 8) | keysum[0]); + if (num != 0xFFFF && num != 0x0) + Dbprintf(" Mifare................"_YELLOW_("%d")"keys", num); + } + + isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET, keysum, 2); + if (isok == 2) { + num = ((keysum[1] << 8) | keysum[0]); + if (num != 0xFFFF && num != 0x0) + Dbprintf(" T55x7................."_YELLOW_("%d")"keys", num); + } + + isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET, keysum, 2); + if (isok == 2) { + num = ((keysum[1] << 8) | keysum[0]); + if (num != 0xFFFF && num != 0x0) + Dbprintf(" iClass................"_YELLOW_("%d")"keys", num); + } + + FlashStop(); +} + - if (!FlashInit()) { - DbpString(" init....................FAIL"); - return; - } - DbpString(" init....................OK"); - - uint8_t dev_id = Flash_ReadID(); - switch (dev_id) { - case 0x11 : - DbpString(" Memory size.............2 mbits / 256kb"); - break; - case 0x10 : - DbpString(" Memory size..... .......1 mbits / 128kb"); - break; - case 0x05 : - DbpString(" Memory size.............512 kbits / 64kb"); - break; - default : - DbpString(" Device ID............... --> Unknown <--"); - break; - } - - uint8_t uid[8] = {0,0,0,0,0,0,0,0}; - Flash_UniqueID(uid); - Dbprintf(" Unique ID...............0x%02x%02x%02x%02x%02x%02x%02x%02x", - uid[7], uid[6], uid[5], uid[4], - uid[3], uid[2], uid[1], uid[0] - ); - - FlashStop(); -} \ No newline at end of file diff --git a/armsrc/flashmem.h b/armsrc/flashmem.h index 198e3392d..4016e66bd 100644 --- a/armsrc/flashmem.h +++ b/armsrc/flashmem.h @@ -23,7 +23,7 @@ * . */ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Common Instructions // +// Common Instructions // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// #ifndef __FLASHMEM_H #define __FLASHMEM_H @@ -32,94 +32,99 @@ #include "apps.h" #include "ticks.h" -// Used Command -#define ID 0x90 -#define MANID 0x90 -#define JEDECID 0x9F +// Used Command +#define ID 0x90 +#define MANID 0x90 +#define JEDECID 0x9F -#define READSTAT1 0x05 -#define READSTAT2 0x35 -#define WRITESTAT 0x01 +#define READSTAT1 0x05 +#define READSTAT2 0x35 +#define WRITESTAT 0x01 -#define WRITEDISABLE 0x04 -#define WRITEENABLE 0x06 +#define WRITEDISABLE 0x04 +#define WRITEENABLE 0x06 -#define READDATA 0x03 -#define PAGEPROG 0x02 +#define READDATA 0x03 +#define FASTREAD 0x0B +#define PAGEPROG 0x02 -#define SECTORERASE 0x20 -#define BLOCK32ERASE 0x52 -#define BLOCK64ERASE 0xD8 -#define CHIPERASE 0xC7 +#define SECTORERASE 0x20 +#define BLOCK32ERASE 0x52 +#define BLOCK64ERASE 0xD8 +#define CHIPERASE 0xC7 -#define UNIQUE_ID 0x4B +#define UNIQUE_ID 0x4B -// Not used or not support command -#define RELEASE 0xAB -#define POWERDOWN 0xB9 -#define FASTREAD 0x0B -#define SUSPEND 0x75 -#define RESUME 0x7A +// Not used or not support command +#define RELEASE 0xAB +#define POWERDOWN 0xB9 +#define SUSPEND 0x75 +#define RESUME 0x7A +// Flash busy timeout: 20ms is the strict minimum when writing 256kb +#define BUSY_TIMEOUT 50000L + +#define WINBOND_MANID 0xEF +#define WINBOND_DEVID 0x11 +#define PAGESIZE 0x100 +#define WINBOND_WRITE_DELAY 0x02 + +#define SPI_CLK 48000000 + +#define BUSY 0x01 +#define WRTEN 0x02 +#define SUS 0x40 + +#define DUMMYBYTE 0xEE +#define NULLBYTE 0x00 +#define NULLINT 0x0000 +#define NO_CONTINUE 0x00 +#define PASS 0x01 +#define FAIL 0x00 +#define maxAddress capacity //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Chip specific instructions // +// List of Error codes // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -//~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~// -#define WINBOND_MANID 0xEF -#define WINBOND_DEVID 0x11 -#define PAGESIZE 0x100 - -//~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~// -#define MICROCHIP_MANID 0xBF -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// Definitions // -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// - -#define SPI_CLK 75000000 //Hex equivalent of 75MHz - -#define BUSY 0x01 -#define WRTEN 0x02 -#define SUS 0x40 - -#define DUMMYBYTE 0xEE -#define NULLBYTE 0x00 -#define NULLINT 0x0000 -#define NO_CONTINUE 0x00 -#define PASS 0x01 -#define FAIL 0x00 -#define maxAddress capacity - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -// List of Error codes // -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#define SUCCESS 0x00 -#define CALLBEGIN 0x01 -#define UNKNOWNCHIP 0x02 -#define UNKNOWNCAP 0x03 -#define CHIPBUSY 0x04 -#define OUTOFBOUNDS 0x05 -#define CANTENWRITE 0x06 -#define PREVWRITTEN 0x07 -#define LOWRAM 0x08 -#define NOSUSPEND 0x09 -#define UNKNOWNERROR 0xFF +#define SUCCESS 0x00 +#define CALLBEGIN 0x01 +#define UNKNOWNCHIP 0x02 +#define UNKNOWNCAP 0x03 +#define CHIPBUSY 0x04 +#define OUTOFBOUNDS 0x05 +#define CANTENWRITE 0x06 +#define PREVWRITTEN 0x07 +#define LOWRAM 0x08 +#define NOSUSPEND 0x09 +#define UNKNOWNERROR 0xFF // List of blocks -#define MAX_BLOCKS 4 -#define MAX_SECTORS 16 +#define MAX_BLOCKS 4 +#define MAX_SECTORS 16 +#define MCK 48000000 +//#define FLASH_BAUD 24000000 +#define FLASH_MINFAST 24000000 //33000000 +#define FLASH_BAUD MCK/2 +#define FLASH_FASTBAUD MCK +#define FLASH_MINBAUD FLASH_FASTBAUD + +#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST) //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -extern void Dbprintf(const char *fmt, ...); +void Dbprintf(const char *fmt, ...); -void FlashSetup(void); +void FlashmemSetSpiBaudrate(uint32_t baudrate); +bool FlashInit(); +void FlashSetup(uint32_t baudrate); void FlashStop(void); bool Flash_WaitIdle(void); uint8_t Flash_ReadStat1(void); uint8_t Flash_ReadStat2(void); uint16_t FlashSendByte(uint32_t data); +void Flash_TransferAdresse(uint32_t address); + +bool Flash_CheckBusy(uint32_t timeout); void Flash_WriteEnable(); bool Flash_WipeMemoryPage(uint8_t page); @@ -128,12 +133,14 @@ bool Flash_Erase4k(uint8_t block, uint8_t sector); //bool Flash_Erase32k(uint32_t address); bool Flash_Erase64k(uint8_t block); -bool FlashInit(); - void Flash_UniqueID(uint8_t *uid); uint8_t Flash_ReadID(void); uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len); +uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len); +uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len); uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len); +uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len); void Flashmem_print_status(void); +void Flashmem_print_info(void); -#endif \ No newline at end of file +#endif diff --git a/armsrc/fonts.c b/armsrc/fonts.c index d79a61d84..78b96e238 100644 --- a/armsrc/fonts.c +++ b/armsrc/fonts.c @@ -7,302 +7,302 @@ //----------------------------------------------------------------------------- const char FONT6x8[97][8] = { - {0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space - {0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00}, // ! - {0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00}, // " - {0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00}, // # - {0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00}, // $ - {0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00}, // % - {0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00}, // & - {0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00}, // ' - {0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00}, // ( - {0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00}, // ) - {0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00}, // * - {0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00}, // + - {0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40}, // , - {0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00}, // - - {0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00}, // . - {0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00}, // / - {0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00}, // 0 - {0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1 - {0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00}, // 2 - {0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00}, // 3 - {0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00}, // 4 - {0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00}, // 5 - {0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00}, // 6 - {0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00}, // 7 - {0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00}, // 8 - {0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00}, // 9 - {0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00}, // : - {0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00}, // ; - {0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00}, // < - {0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00}, // = - {0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00}, // > - {0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00}, // ? - {0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00}, // @ - {0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00}, // A - {0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00}, // B - {0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00}, // C - {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00}, // D - {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00}, // E - {0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00}, // F - {0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00}, // G - {0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00}, // H - {0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // I - {0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00}, // J - {0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00}, // K - {0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00}, // L - {0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00}, // M - {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00}, // N - {0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // O - {0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00}, // P - {0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00}, // Q - {0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00}, // R - {0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00}, // S - {0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00}, // T - {0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // U - {0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00}, // V - {0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00}, // W - {0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00}, // X - {0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00}, // Y - {0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00}, // Z - {0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00}, // [ - {0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00}, // backslash - {0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00}, // ] - {0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00}, // ^ - {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00}, // _ - {0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00}, // ` - {0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00}, // a - {0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00}, // b - {0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00}, // c - {0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00}, // d - {0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00}, // e - {0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00}, // f - {0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70}, // g - {0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00}, // h - {0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00}, // i - {0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00}, // j - {0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00}, // k - {0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // l - {0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00}, // m - {0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00}, // n - {0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00}, // o - {0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80}, // p - {0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08}, // q - {0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00}, // r - {0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00}, // s - {0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00}, // t - {0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00}, // u - {0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00}, // v - {0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00}, // w - {0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00}, // x - {0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70}, // y - {0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00}, // z - {0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00}, // { - {0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00}, // | - {0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00}, // } - {0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00}, // ~ - {0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00} // DEL + {0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // columns, rows, bytes per char + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space + {0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00}, // ! + {0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00}, // " + {0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00}, // # + {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, // $ + {0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18, 0x00}, // % + {0x40, 0xA0, 0xA0, 0x40, 0xA8, 0x90, 0x68, 0x00}, // & + {0x30, 0x30, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00}, // ' + {0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00}, // ( + {0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00}, // ) + {0x00, 0x20, 0xA8, 0x70, 0x70, 0xA8, 0x20, 0x00}, // * + {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, // + + {0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x20, 0x40}, // , + {0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00}, // - + {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00}, // . + {0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00}, // / + {0x70, 0x88, 0x88, 0xA8, 0x88, 0x88, 0x70, 0x00}, // 0 + {0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // 1 + {0x70, 0x88, 0x08, 0x70, 0x80, 0x80, 0xF8, 0x00}, // 2 + {0xF8, 0x08, 0x10, 0x30, 0x08, 0x88, 0x70, 0x00}, // 3 + {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, // 4 + {0xF8, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70, 0x00}, // 5 + {0x38, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70, 0x00}, // 6 + {0xF8, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, // 7 + {0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00}, // 8 + {0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0xE0, 0x00}, // 9 + {0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00}, // : + {0x00, 0x00, 0x20, 0x00, 0x20, 0x20, 0x40, 0x00}, // ; + {0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00}, // < + {0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00}, // = + {0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00}, // > + {0x70, 0x88, 0x08, 0x30, 0x20, 0x00, 0x20, 0x00}, // ? + {0x70, 0x88, 0xA8, 0xB8, 0xB0, 0x80, 0x78, 0x00}, // @ + {0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00}, // A + {0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0, 0x00}, // B + {0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00}, // C + {0xF0, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF0, 0x00}, // D + {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00}, // E + {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00}, // F + {0x78, 0x88, 0x80, 0x80, 0x98, 0x88, 0x78, 0x00}, // G + {0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00}, // H + {0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // I + {0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, // J + {0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00}, // K + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00}, // L + {0x88, 0xD8, 0xA8, 0xA8, 0xA8, 0x88, 0x88, 0x00}, // M + {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, // N + {0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00}, // O + {0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00}, // P + {0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68, 0x00}, // Q + {0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00}, // R + {0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00}, // S + {0xF8, 0xA8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, // T + {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00}, // U + {0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00}, // V + {0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50, 0x00}, // W + {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, // X + {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, // Y + {0xF8, 0x08, 0x10, 0x70, 0x40, 0x80, 0xF8, 0x00}, // Z + {0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x78, 0x00}, // [ + {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00}, // backslash + {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}, // ] + {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, // ^ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00}, // _ + {0x60, 0x60, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00}, // ` + {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x78, 0x00}, // a + {0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00}, // b + {0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00}, // c + {0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00}, // d + {0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00}, // e + {0x10, 0x28, 0x20, 0x70, 0x20, 0x20, 0x20, 0x00}, // f + {0x00, 0x00, 0x70, 0x98, 0x98, 0x68, 0x08, 0x70}, // g + {0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00}, // h + {0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00}, // i + {0x10, 0x00, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, // j + {0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x00}, // k + {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // l + {0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00}, // m + {0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00}, // n + {0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00}, // o + {0x00, 0x00, 0xB0, 0xC8, 0xC8, 0xB0, 0x80, 0x80}, // p + {0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x08}, // q + {0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00}, // r + {0x00, 0x00, 0x78, 0x80, 0x70, 0x08, 0xF0, 0x00}, // s + {0x20, 0x20, 0xF8, 0x20, 0x20, 0x28, 0x10, 0x00}, // t + {0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00}, // u + {0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00}, // v + {0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50, 0x00}, // w + {0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00}, // x + {0x00, 0x00, 0x88, 0x88, 0x78, 0x08, 0x88, 0x70}, // y + {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, // z + {0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10, 0x00}, // { + {0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00}, // | + {0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40, 0x00}, // } + {0x40, 0xA8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, // ~ + {0x70, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00} // DEL }; /* const char FONT8x8F[97][8] = { - {0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space - {0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // ! - {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // " - {0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // # - {0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $ - {0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // % - {0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // & - {0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // ' - {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // ( - {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // ) - {0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // * - {0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // + - {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // , - {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // - - {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // . - {0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // / - {0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0 - {0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1 - {0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2 - {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3 - {0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4 - {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5 - {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6 - {0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7 - {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8 - {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9 - {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // : - {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ; - {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // < - {0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // = - {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // > - {0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ? - {0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @ - {0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A - {0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B - {0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C - {0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D - {0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E - {0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F - {0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G - {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H - {0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I - {0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J - {0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K - {0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L - {0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M - {0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N - {0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O - {0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P - {0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q - {0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R - {0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S - {0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T - {0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U - {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V - {0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W - {0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X - {0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y - {0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z - {0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [ - {0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash - {0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ] - {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^ - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _ - {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // ` - {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a - {0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b - {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c - {0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d - {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e - {0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f - {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g - {0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h - {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i - {0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j - {0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k - {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l - {0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m - {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n - {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o - {0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p - {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q - {0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r - {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s - {0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t - {0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u - {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v - {0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w - {0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x - {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y - {0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z - {0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // { - {0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // | - {0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // } - {0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~ - {0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL + {0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space + {0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // ! + {0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // " + {0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // # + {0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $ + {0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // % + {0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // & + {0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // ' + {0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // ( + {0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // ) + {0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // * + {0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // + + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // , + {0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // - + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // . + {0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // / + {0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0 + {0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1 + {0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2 + {0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3 + {0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4 + {0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5 + {0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6 + {0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7 + {0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8 + {0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9 + {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // : + {0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ; + {0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // < + {0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // = + {0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // > + {0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ? + {0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @ + {0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A + {0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B + {0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C + {0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D + {0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E + {0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F + {0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G + {0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H + {0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I + {0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J + {0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K + {0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L + {0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M + {0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N + {0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O + {0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P + {0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q + {0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R + {0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S + {0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T + {0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U + {0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V + {0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W + {0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X + {0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y + {0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z + {0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [ + {0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash + {0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ] + {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _ + {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // ` + {0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a + {0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b + {0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c + {0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d + {0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e + {0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f + {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g + {0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h + {0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i + {0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j + {0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k + {0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l + {0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m + {0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n + {0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o + {0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p + {0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q + {0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r + {0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s + {0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t + {0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u + {0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v + {0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w + {0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x + {0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y + {0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z + {0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // { + {0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // | + {0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // } + {0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~ + {0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL }; const char FONT8x16[97][16] = { - {0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space - {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // ! - {0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // " - {0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // # - {0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $ - {0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // % - {0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // & - {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ' - {0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // ( - {0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // ) - {0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // * - {0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // + - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // , - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // - - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // . - {0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // / - {0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0 - {0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1 - {0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2 - {0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3 - {0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4 - {0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5 - {0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6 - {0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7 - {0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8 - {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9 - {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // : - {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ; - {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // < - {0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // = - {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // > - {0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ? - {0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @ - {0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A - {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B - {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C - {0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D - {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E - {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F - {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G - {0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H - {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I - {0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J - {0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K - {0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L - {0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M - {0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N - {0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O - {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P - {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q - {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R - {0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S - {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T - {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U - {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V - {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W - {0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X - {0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y - {0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z - {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [ - {0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash - {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ] - {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^ - {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _ - {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ` - {0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a - {0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b - {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c - {0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d - {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e - {0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f - {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g - {0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h - {0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i - {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j - {0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k - {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l - {0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m - {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n - {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o - {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p - {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q - {0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r - {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s - {0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t - {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u - {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v - {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w - {0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x - {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y - {0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z - {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // { - {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // | - {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // } - {0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~ - {0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL + {0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space + {0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // ! + {0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // " + {0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // # + {0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $ + {0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // % + {0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // & + {0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ' + {0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // ( + {0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // ) + {0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // * + {0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // + + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // , + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // - + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // . + {0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // / + {0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0 + {0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1 + {0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2 + {0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3 + {0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4 + {0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5 + {0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6 + {0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7 + {0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8 + {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9 + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // : + {0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ; + {0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // < + {0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // = + {0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // > + {0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ? + {0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @ + {0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A + {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B + {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C + {0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D + {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E + {0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F + {0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G + {0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H + {0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I + {0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J + {0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K + {0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L + {0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M + {0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N + {0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O + {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P + {0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q + {0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R + {0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S + {0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T + {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U + {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V + {0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W + {0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X + {0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y + {0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z + {0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [ + {0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash + {0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ] + {0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _ + {0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ` + {0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a + {0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b + {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c + {0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d + {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e + {0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f + {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g + {0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h + {0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i + {0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j + {0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k + {0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l + {0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m + {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n + {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o + {0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p + {0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q + {0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r + {0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s + {0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t + {0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u + {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v + {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w + {0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x + {0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y + {0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z + {0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // { + {0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // | + {0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // } + {0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~ + {0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL }; */ diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index e4ab1ab0b..7e920a360 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -21,15 +21,15 @@ 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 +#define OUTPUT_BUFFER_LEN 80 //----------------------------------------------------------------------------- // Set up the Serial Peripheral Interface as master // Used to write the FPGA config word // May also be used to write to other SPI attached devices like an LCD //----------------------------------------------------------------------------- -static void DisableSpi(void) { - //* Reset all the Chip Select register +static void DisableSpi(void) { + //* Reset all the Chip Select register AT91C_BASE_SPI->SPI_CSR[0] = 0; AT91C_BASE_SPI->SPI_CSR[1] = 0; AT91C_BASE_SPI->SPI_CSR[2] = 0; @@ -40,121 +40,116 @@ static void DisableSpi(void) { // Disable all interrupts AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF; - - // SPI disable - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; + + // SPI disable + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; } void SetupSpi(int mode) { - // PA1 -> SPI_NCS3 chip select (MEM) - // PA10 -> SPI_NCS2 chip select (LCD) - // PA11 -> SPI_NCS0 chip select (FPGA) - // PA12 -> SPI_MISO Master-In Slave-Out - // PA13 -> SPI_MOSI Master-Out Slave-In - // PA14 -> SPI_SPCK Serial Clock + // PA1 -> SPI_NCS3 chip select (MEM) + // PA10 -> SPI_NCS2 chip select (LCD) + // PA11 -> SPI_NCS0 chip select (FPGA) + // PA12 -> SPI_MISO Master-In Slave-Out + // PA13 -> SPI_MOSI Master-Out Slave-In + // PA14 -> SPI_SPCK Serial Clock - // Disable PIO control of the following pins, allows use by the SPI peripheral - AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK; + // Disable PIO control of the following pins, allows use by the SPI peripheral + AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK; - // Peripheral A - AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK; + // Peripheral A + AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK; - // Peripheral B - //AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2; + // Peripheral B + //AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2; - //enable the SPI Peripheral clock - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI); - // Enable SPI - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; + //enable the SPI Peripheral clock + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI); + // Enable SPI + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; - switch (mode) { - case SPI_FPGA_MODE: - AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (0xE << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) - ( 0 << 7) | // Local Loopback Disabled - AT91C_SPI_MODFDIS | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - AT91C_SPI_PS_FIXED | // Fixed Peripheral Select - AT91C_SPI_MSTR; // 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 - AT91C_SPI_BITS_16 | // Bits per Transfer (16 bits) - ( 0 << 3) | // Chip Select inactive after transfer - AT91C_SPI_NCPHA | // 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) - (0xB << 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 - AT91C_SPI_BITS_9 | // 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: - DisableSpi(); - break; - } + switch (mode) { + case SPI_FPGA_MODE: + AT91C_BASE_SPI->SPI_MR = + (0 << 24) | // Delay between chip selects (take default: 6 MCK periods) + (0xE << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) + (0 << 7) | // Local Loopback Disabled + AT91C_SPI_MODFDIS | // Mode Fault Detection disabled + (0 << 2) | // Chip selects connected directly to peripheral + AT91C_SPI_PS_FIXED | // Fixed Peripheral Select + AT91C_SPI_MSTR; // 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 + AT91C_SPI_BITS_16 | // Bits per Transfer (16 bits) + (0 << 3) | // Chip Select inactive after transfer + AT91C_SPI_NCPHA | // 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) + (0xB << 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 + AT91C_SPI_BITS_9 | // 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: + DisableSpi(); + break; + } } //----------------------------------------------------------------------------- // 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 FpgaSetupSscExt(uint8_t clearPCER) { - // 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_CLK; - AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; - - if ( clearPCER ) - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC); - else - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_SSC); - - // 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 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 bits per transfer, no loopback, MSB first, 1 transfer per sync - // pulse, no output sync - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - - // 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; - - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; -} void FpgaSetupSsc(void) { - FpgaSetupSscExt(true); + // 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_CLK; + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; + + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC); + + // 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 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 bits per transfer, no loopback, MSB first, 1 transfer per sync + // pulse, no output sync + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); + + // 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; + + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; } + //----------------------------------------------------------------------------- // Set up DMA to receive samples from the FPGA. We will use the PDC, with // a single buffer as a circular buffer (so that we just chain back to @@ -162,15 +157,15 @@ void FpgaSetupSsc(void) { // is in apps.h, because it should be inlined, for speed. //----------------------------------------------------------------------------- bool FpgaSetupSscDma(uint8_t *buf, int len) { - if (buf == NULL) return false; + if (buf == NULL) return false; - FpgaDisableSscDma(); - 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 - FpgaEnableSscDma(); - return true; + FpgaDisableSscDma(); + 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 + FpgaEnableSscDma(); + return true; } //---------------------------------------------------------------------------- @@ -178,20 +173,20 @@ bool FpgaSetupSscDma(uint8_t *buf, int len) { // each call. //---------------------------------------------------------------------------- static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer) { - 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 (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 (res != Z_OK) + Dbprintf("inflate returned: %d, %s", res, compressed_fpga_stream->msg); - if (res < 0) - return res; - } - uncompressed_bytes_cnt++; - return *fpga_image_ptr++; + if (res < 0) + return res; + } + uncompressed_bytes_cnt++; + return *fpga_image_ptr++; } //---------------------------------------------------------------------------- @@ -200,140 +195,143 @@ static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8 // 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); - } + 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); + 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); + return BigBuf_malloc(items * size); } // free eventually allocated BigBuf memory static void fpga_inflate_free(voidpf opaque, voidpf address) { - BigBuf_free(); BigBuf_Clear_ext(false); + 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]; + uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE]; - uncompressed_bytes_cnt = 0; + 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; + // 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); + int res = inflateInit2(compressed_fpga_stream, 0); + if (res < 0) + return false; - fpga_image_ptr = output_buffer; + 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); + 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; + // 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; - return false; + return false; } -static void DownloadFPGA_byte(unsigned char w) { +static void DownloadFPGA_byte(uint8_t 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 + AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON; + AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON; + HIGH(GPIO_FPGA_ON); // ensure everything is powered on - SpinDelay(50); + SpinDelay(50); - LED_D_ON(); + LED_D_ON(); - // These pins are inputs + // These pins are inputs AT91C_BASE_PIOA->PIO_ODR = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; - // PIO controls the following pins + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; + // PIO controls the following pins AT91C_BASE_PIOA->PIO_PER = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; - // Enable pull-ups - AT91C_BASE_PIOA->PIO_PPUER = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; + // Enable pull-ups + AT91C_BASE_PIOA->PIO_PPUER = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; - // setup initial logic state - HIGH(GPIO_FPGA_NPROGRAM); - LOW(GPIO_FPGA_CCLK); - LOW(GPIO_FPGA_DIN); - // These pins are outputs - AT91C_BASE_PIOA->PIO_OER = - GPIO_FPGA_NPROGRAM | - GPIO_FPGA_CCLK | - GPIO_FPGA_DIN; + // setup initial logic state + HIGH(GPIO_FPGA_NPROGRAM); + LOW(GPIO_FPGA_CCLK); + LOW(GPIO_FPGA_DIN); + // These pins are outputs + AT91C_BASE_PIOA->PIO_OER = + GPIO_FPGA_NPROGRAM | + GPIO_FPGA_CCLK | + GPIO_FPGA_DIN; - // enter FPGA configuration mode - LOW(GPIO_FPGA_NPROGRAM); - SpinDelay(50); - HIGH(GPIO_FPGA_NPROGRAM); + // enter FPGA configuration mode + LOW(GPIO_FPGA_NPROGRAM); + SpinDelay(50); + HIGH(GPIO_FPGA_NPROGRAM); - i = 100000; - // wait for FPGA ready to accept data signal - while ((i) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT ) ) ) { - i--; - } + i = 100000; + // wait for FPGA ready to accept data signal + while ((i) && (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT))) { + i--; + } - // crude error indicator, leave both red LEDs on and return - if (i==0){ - LED_C_ON(); - LED_D_ON(); - return; - } + // crude error indicator, leave both red LEDs on and return + if (i == 0) { + LED_C_ON(); + LED_D_ON(); + 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; - } - DownloadFPGA_byte(b); - } + 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; + } + DownloadFPGA_byte(b); + } - // continue to clock FPGA until ready signal goes high - i = 100000; - while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) { - HIGH(GPIO_FPGA_CCLK); - LOW(GPIO_FPGA_CCLK); - } - // crude error indicator, leave both red LEDs on and return - if (i==0){ - LED_C_ON(); - LED_D_ON(); - return; - } - LED_D_OFF(); + // continue to clock FPGA until ready signal goes high + i = 100000; + while ((i--) && (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE))) { + HIGH(GPIO_FPGA_CCLK); + LOW(GPIO_FPGA_CCLK); + } + // crude error indicator, leave both red LEDs on and return + if (i == 0) { + LED_C_ON(); + LED_D_ON(); + return; + } + LED_D_OFF(); } /* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence @@ -343,48 +341,48 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp * length. */ static int bitparse_find_section(int bitstream_version, char section_name, uint32_t *section_length, z_streamp compressed_fpga_stream, uint8_t *output_buffer) { - 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++; - uint32_t current_length = 0; - if (current_name < 'a' || current_name > 'e') { - /* Strange section name, abort */ - break; - } - current_length = 0; - 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; - 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; - } + 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++; + uint32_t current_length = 0; + if (current_name < 'a' || current_name > 'e') { + /* Strange section name, abort */ + break; + } + current_length = 0; + 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; + 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; + } - if (current_name != 'e' && current_length > 255) { - /* Maybe a parse error */ - break; - } + if (current_name != 'e' && current_length > 255) { + /* Maybe a parse error */ + break; + } - if (current_name == section_name) { - /* Found it */ - *section_length = current_length; - result = 1; - break; - } + if (current_name == section_name) { + /* Found it */ + *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++; - } - } - return result; + 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++; + } + } + return result; } //---------------------------------------------------------------------------- @@ -393,34 +391,36 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3 //---------------------------------------------------------------------------- void FpgaDownloadAndGo(int bitstream_version) { - // check whether or not the bitstream is already loaded - if (downloaded_bitstream == bitstream_version) - return; - - z_stream compressed_fpga_stream; - uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; + // check whether or not the bitstream is already loaded + if (downloaded_bitstream == bitstream_version) + return; - bool verbose = (MF_DBGLEVEL > 3); - - // make sure that we have enough memory to decompress - BigBuf_free(); BigBuf_Clear_ext(verbose); + z_stream compressed_fpga_stream; + uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; - if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) - return; + bool verbose = (DBGLEVEL > 3); - uint32_t 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; - } + // make sure that we have enough memory to decompress + BigBuf_free(); + BigBuf_Clear_ext(verbose); - inflateEnd(&compressed_fpga_stream); + if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) + return; - // turn off antenna - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); + uint32_t 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); } //----------------------------------------------------------------------------- @@ -429,10 +429,10 @@ void FpgaDownloadAndGo(int bitstream_version) { // where C is the 4 bit command and D is the 12 bit data //----------------------------------------------------------------------------- void FpgaSendCommand(uint16_t cmd, uint16_t v) { - SetupSpi(SPI_FPGA_MODE); - 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 - while (!(AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF)) {}; // wait till transfer is complete + SetupSpi(SPI_FPGA_MODE); + 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 + while (!(AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF)) {}; // wait till transfer is complete } //----------------------------------------------------------------------------- // Write the FPGA setup word (that determines what mode the logic is in, read @@ -440,7 +440,7 @@ void FpgaSendCommand(uint16_t cmd, uint16_t v) { // avoid changing this function's occurence everywhere in the source code. //----------------------------------------------------------------------------- void FpgaWriteConfWord(uint8_t v) { - FpgaSendCommand(FPGA_CMD_SET_CONFREG, v); + FpgaSendCommand(FPGA_CMD_SET_CONFREG, v); } //----------------------------------------------------------------------------- @@ -449,46 +449,57 @@ void FpgaWriteConfWord(uint8_t v) { // the samples from the ADC always flow through the FPGA. //----------------------------------------------------------------------------- void SetAdcMuxFor(uint32_t whichGpio) { - AT91C_BASE_PIOA->PIO_OER = - GPIO_MUXSEL_HIPKD | - GPIO_MUXSEL_LOPKD | - GPIO_MUXSEL_LORAW | - GPIO_MUXSEL_HIRAW; - AT91C_BASE_PIOA->PIO_PER = - GPIO_MUXSEL_HIPKD | - GPIO_MUXSEL_LOPKD | - GPIO_MUXSEL_LORAW | - GPIO_MUXSEL_HIRAW; +#ifndef WITH_FPC_USART + // When compiled without FPC USART support + AT91C_BASE_PIOA->PIO_OER = + GPIO_MUXSEL_HIPKD | + GPIO_MUXSEL_LOPKD | + GPIO_MUXSEL_LORAW | + GPIO_MUXSEL_HIRAW; - LOW(GPIO_MUXSEL_HIPKD); - LOW(GPIO_MUXSEL_LOPKD); -#ifndef WITH_FPC - LOW(GPIO_MUXSEL_HIRAW); - LOW(GPIO_MUXSEL_LORAW); -#endif + AT91C_BASE_PIOA->PIO_PER = + GPIO_MUXSEL_HIPKD | + GPIO_MUXSEL_LOPKD | + GPIO_MUXSEL_LORAW | + GPIO_MUXSEL_HIRAW; + + LOW(GPIO_MUXSEL_HIPKD); + LOW(GPIO_MUXSEL_LOPKD); + LOW(GPIO_MUXSEL_HIRAW); + LOW(GPIO_MUXSEL_LORAW); + HIGH(whichGpio); +#else + if ((whichGpio == GPIO_MUXSEL_LORAW) || (whichGpio == GPIO_MUXSEL_HIRAW)) + return; + // FPC USART uses HIRAW/LOWRAW pins, so they are excluded here. + AT91C_BASE_PIOA->PIO_OER = GPIO_MUXSEL_HIPKD | GPIO_MUXSEL_LOPKD; + AT91C_BASE_PIOA->PIO_PER = GPIO_MUXSEL_HIPKD | GPIO_MUXSEL_LOPKD; + LOW(GPIO_MUXSEL_HIPKD); + LOW(GPIO_MUXSEL_LOPKD); + HIGH(whichGpio); +#endif - HIGH(whichGpio); } void Fpga_print_status(void) { - Dbprintf("Currently loaded FPGA image"); - Dbprintf(" mode....................%s", fpga_version_information[downloaded_bitstream-1]); + DbpString(_BLUE_("Currently loaded FPGA image")); + Dbprintf(" mode....................%s", fpga_version_information[downloaded_bitstream - 1]); } int FpgaGetCurrent(void) { - return downloaded_bitstream; + return downloaded_bitstream; } -// Turns off the antenna, +// Turns off the antenna, // log message // if HF, Disable SSC DMA // turn off trace and leds off. -void switch_off(void) { - if (MF_DBGLEVEL > 3) Dbprintf("switch_off"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - if (downloaded_bitstream == FPGA_BITSTREAM_HF ) - FpgaDisableSscDma(); - set_tracing(false); - LEDsoff(); +void switch_off(void) { + if (DBGLEVEL > 3) Dbprintf("switch_off"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + if (downloaded_bitstream == FPGA_BITSTREAM_HF) + FpgaDisableSscDma(); + set_tracing(false); + LEDsoff(); } diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 21731b571..f9b0e44b0 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -16,29 +16,28 @@ #include #include "apps.h" #include "fpga.h" -#include "common.h" // standard definitions -#include "proxmark3.h" // common area +#include "common.h" // standard definitions +#include "proxmark3.h" // common area #include "string.h" -#include "BigBuf.h" // bigbuf mem -#include "zlib.h" // uncompress +#include "BigBuf.h" // bigbuf mem +#include "zlib.h" // uncompress void FpgaSendCommand(uint16_t cmd, uint16_t v); void FpgaWriteConfWord(uint8_t v); void FpgaDownloadAndGo(int bitstream_version); // void FpgaGatherVersion(int bitstream_version, char *dst, int len); -void FpgaSetupSscExt(uint8_t clearPCER); void FpgaSetupSsc(void); void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, int len); void Fpga_print_status(void); int FpgaGetCurrent(void); -#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; +#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); // extern and generel turn off the antenna method -extern void switch_off(void); +void switch_off(void); // definitions for multiple FPGA config files support #define FPGA_BITSTREAM_LF 1 @@ -46,54 +45,56 @@ extern void switch_off(void); //#define FPGA_BITSTREAM_FELICA 3 // Definitions for the FPGA commands. -#define FPGA_CMD_SET_CONFREG (1<<12) -#define FPGA_CMD_SET_DIVISOR (2<<12) -#define FPGA_CMD_SET_USER_BYTE1 (3<<12) +#define FPGA_CMD_SET_CONFREG (1<<12) +#define FPGA_CMD_SET_DIVISOR (2<<12) +#define FPGA_CMD_SET_USER_BYTE1 (3<<12) // Definitions for the FPGA configuration word. // LF -#define FPGA_MAJOR_MODE_LF_ADC (0<<5) -#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) -#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) +#define FPGA_MAJOR_MODE_LF_ADC (0<<5) +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) +#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) // HF -#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) -#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) -#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) -#define FPGA_MAJOR_MODE_HF_FELICA (5<<5) +#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) +#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) +#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) +#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) +#define FPGA_MAJOR_MODE_HF_FELICA (5<<5) // BOTH -#define FPGA_MAJOR_MODE_OFF (7<<5) +#define FPGA_MAJOR_MODE_OFF_LF (6<<5) +#define FPGA_MAJOR_MODE_OFF (7<<5) + // Options for LF_ADC -#define FPGA_LF_ADC_READER_FIELD (1<<0) +#define FPGA_LF_ADC_READER_FIELD (1<<0) // Options for LF_EDGE_DETECT -#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 -#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) -#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) +#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 +#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) +#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) // Options for the HF reader, tx to tag -#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) +#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 (1<<2) +#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 (1<<2) // Options for the HF simulated tag, how to modulate -#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) // 0000 -#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) // 0001 -#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) // 0010 -#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) // 0100 -#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101 -// no 848K +#define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000 +#define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001 +#define FPGA_HF_SIMULATOR_MODULATE_212K 0x2 // 0010 +#define FPGA_HF_SIMULATOR_MODULATE_424K 0x4 // 0100 +#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101 +// no 848K // 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) +#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) -//options for Felica. -#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000 +//options for Felica. +#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000 #define FPGA_HF_ISO18092_FLAG_NOMOD (1<<0) // 0001 disable modulation module #define FPGA_HF_ISO18092_FLAG_424K (2<<0) // 0010 should enable 414k mode (untested). No autodetect -#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag - -#endif \ No newline at end of file +#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag + +#endif diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index 06ec03ed6..bb5d8699c 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -2,79 +2,78 @@ #include "apps.h" #include "BigBuf.h" #include "util.h" -#include "usb_cdc.h" // for usb_poll_validate_length +#include "usb_cdc.h" // for usb_poll_validate_length -static void RAMFUNC optimizedSnoop(void); +static void RAMFUNC optimizedSniff(void); -static void RAMFUNC optimizedSnoop(void) -{ - int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory +static void RAMFUNC optimizedSniff(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-1; + uint16_t *dest = (uint16_t *)BigBuf_get_addr(); + uint16_t *destend = dest + n - 1; - // Reading data loop - while(dest <= destend) { - if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - *dest = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); - dest++; - } - } - //setting tracelen - importsnt! it was set by buffer overflow before - set_tracelen( BigBuf_max_traceLen()); + // Reading data loop + while (dest <= destend) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + *dest = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); + dest++; + } + } + //setting tracelen - important! it was set by buffer overflow before + set_tracelen(BigBuf_max_traceLen()); } -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 = 0; +void HfSniff(int samplesToSkip, int triggersToSkip) { + BigBuf_free(); + BigBuf_Clear(); - LED_D_ON(); + Dbprintf("Skipping first %d sample pairs, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); + int trigger_cnt = 0; - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Set up the synchronous serial port - FpgaSetupSsc(); + LED_D_ON(); - // Setting Frame Mode For better performance on high speed data transfer. - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Set up the synchronous serial port + FpgaSetupSsc(); + + // Setting Frame Mode For better performance on high speed data transfer. + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); SpinDelay(100); - - 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); + + uint16_t r = 0; + while (!BUTTON_PRESS() && !data_available()) { + 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 >= 180) { // 0xB4 ?? if (++trigger_cnt > triggersToSkip) - break; - } - } - } + 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); - } + if (!BUTTON_PRESS()) { + int waitcount = samplesToSkip; // lets wait 40000 ticks of pck0 + while (waitcount != 0) { - //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); + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) + waitcount--; + } + optimizedSniff(); + Dbprintf("Trigger kicked! Value: %d, Dumping Samples Hispeed now.", r); + } - DbpString("HF Snoop end"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + //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); + + DbpString("HF Sniffing end"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); } diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 6095d1639..2a7cf2859 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -3,46 +3,35 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Hitag2 emulation (preliminary test version) +// Hitag2 emulation // // (c) 2009 Henryk Plötz //----------------------------------------------------------------------------- // Hitag2 complete rewrite of the code // - Fixed modulation/encoding issues // - Rewrote code for transponder emulation -// - Added snooping of transponder communication +// - Added sniffing of transponder communication // - Added reader functionality // // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- +// Piwi, 2019 +// Iceman, 2019 +#include "hitag2.h" +#include "hitag2_crypto.h" +#include "hitag.h" #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" #include "string.h" #include "BigBuf.h" -static bool bQuiet; static bool bCrypto; static bool bAuthenticating; static bool bPwd; static bool bSuccessful; -struct hitag2_tag { - uint32_t uid; - enum { - TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr - TAG_STATE_ACTIVATING = 0x02 , // In activation phase (password mode), sent UID, awaiting reader password - TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands - TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written - } state; - unsigned int active_sector; - uint8_t crypto_active; - uint64_t cs; - uint8_t sectors[12][4]; -}; - static struct hitag2_tag tag = { .state = TAG_STATE_RESET, .sectors = { // Password mode: | Crypto mode: @@ -62,16 +51,16 @@ static struct hitag2_tag tag = { }; static enum { - WRITE_STATE_START = 0x0, - WRITE_STATE_PAGENUM_WRITTEN, - WRITE_STATE_PROG + WRITE_STATE_START = 0x0, + WRITE_STATE_PAGENUM_WRITTEN, + WRITE_STATE_PROG } writestate; - -// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. + +// 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 uint8_t *auth_table; static size_t auth_table_pos = 0; static size_t auth_table_len = AUTH_TABLE_LENGTH; @@ -81,1711 +70,1548 @@ static uint8_t key[8]; static uint8_t writedata[4]; static 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. -// For educational purposes only. -// 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) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) - -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 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; - - return (ht2_f5c >> i5) & 1; -} - -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++) - { - x >>= 1; - x += (u64) (_f20 (x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; - } - return x; -} - -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); - - *state = x; - return _f20 (x); -} - -// "MIKRON" = O N M I K R -// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key -// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear -// Random = 65 6E 45 72 - Random IV, transmitted in clear -//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream - -// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6". -// The inverse of the first 4 bytes is sent to the tag to authenticate. -// The rest is encrypted by XORing it with the subsequent keystream. - -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) { - tag.state = TAG_STATE_RESET; - tag.crypto_active = 0; - return 0; + tag.state = TAG_STATE_RESET; + tag.crypto_active = 0; + return 0; } static int hitag2_init(void) { - 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); - 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_)); -} - -static int hitag2_cipher_authenticate(uint64_t* cs, const uint8_t *authenticator_is) -{ - uint8_t authenticator_should[4]; - authenticator_should[0] = ~_hitag2_byte(cs); - authenticator_should[1] = ~_hitag2_byte(cs); - authenticator_should[2] = ~_hitag2_byte(cs); - authenticator_should[3] = ~_hitag2_byte(cs); - 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) -{ - int 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 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_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_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_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 static void hitag_send_bit(int bit) { - LED_A_ON(); - // 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) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - 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); - } else { - // Manchester: Loaded, then unloaded |--__| - 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); - } - LED_A_OFF(); + LED_A_ON(); + // 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) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + 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); + } else { + // Manchester: Loaded, then unloaded |--__| + 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); + } + LED_A_OFF(); } -static void hitag_send_frame(const uint8_t* frame, size_t frame_len) -{ - // Send start of frame - for(size_t i=0; i<5; i++) { - hitag_send_bit(1); - } +static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { + // SOF - send start of frame + hitag_send_bit(1); + hitag_send_bit(1); + hitag_send_bit(1); + hitag_send_bit(1); + hitag_send_bit(1); - // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&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); + // Drop the modulation + LOW(GPIO_SSC_DOUT); } +// sim +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]; -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]; - - // Copy the (original) received frame how it is send over the air - memcpy(rx_air,rx,nbytes(rxlen)); + // Copy the (original) received frame how it is send over the air + memcpy(rx_air, rx, nbytes(rxlen)); - if(tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); - } - - // 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 - case 05: { - // Always send over the air in the clear plaintext mode - if(rx_air[0] != 0xC0) { - // Unknown frame ? - return; - } - *txlen = 32; - memcpy(tx,tag.sectors[0],4); - tag.crypto_active = 0; - } - break; + if (tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen / 8, rxlen % 8); + } - // 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); - // Verify complement of sector index - if(sector != ((rx[0]>>3)&0x07)) { - //DbpString("Transmission error (read/write)"); - return; - } + // Reset the transmission frame length + *txlen = 0; - switch (rx[0] & 0xC6) { - // Read command: 11xx x00y - case 0xC0: - memcpy(tx,tag.sectors[sector],4); - *txlen = 32; - 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; + // 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 + case 05: { + // Always send over the air in the clear plaintext mode + if (rx_air[0] != 0xC0) { + // Unknown frame ? + return; + } + *txlen = 32; + memcpy(tx, tag.sectors[0], 4); + tag.crypto_active = 0; + } + break; - // Write command: 10xx x01y - case 0x82: - // Prepare write, acknowledge by repeating command - memcpy(tx,rx,nbytes(rxlen)); - *txlen = rxlen; - tag.active_sector = sector; - tag.state=TAG_STATE_WRITING; - break; - - // Unknown command - default: - Dbprintf("Unknown command: %02x %02x",rx[0],rx[1]); - return; - break; - } - } - break; + // 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); + // Verify complement of sector index + if (sector != ((rx[0] >> 3) & 0x07)) { + //DbpString("Transmission error (read/write)"); + return; + } - // Writing data or Reader password - case 32: { - 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; - return; - } else { - // Received RWD password, respond with configuration and our password - if(memcmp(rx,tag.sectors[1],4) != 0) { - DbpString("Reader password is wrong"); - return; - } - *txlen = 32; - memcpy(tx,tag.sectors[3],4); - } - } - break; + switch (rx[0] & 0xC6) { + // Read command: 11xx x00y + case 0xC0: + memcpy(tx, tag.sectors[sector], 4); + *txlen = 32; + break; - // Received RWD authentication challenge and respnse - case 64: { - // Store the authentication attempt - if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { - memcpy(auth_table+auth_table_len,rx,8); - auth_table_len += 8; - } + // 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; - // Reset the cipher state - hitag2_cipher_reset(&tag,rx); - // Check if the authentication was correct - 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]); - return; - } - // Succesful, but commented out reporting back to the Host, this may delay to much. - // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + // Write command: 10xx x01y + case 0x82: + // Prepare write, acknowledge by repeating command + memcpy(tx, rx, nbytes(rxlen)); + *txlen = rxlen; + tag.active_sector = sector; + tag.state = TAG_STATE_WRITING; + break; - // Activate encryption algorithm for all further communication - tag.crypto_active = 1; + // Unknown command + default: + Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); + return; + break; + } + } + break; - // Use the tag password as response - memcpy(tx,tag.sectors[3],4); - *txlen = 32; - } - break; - } + // Writing data or Reader password + case 32: { + 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; + return; + } else { + // Received RWD password, respond with configuration and our password + if (memcmp(rx, tag.sectors[1], 4) != 0) { + DbpString("Reader password is wrong"); + return; + } + *txlen = 32; + memcpy(tx, tag.sectors[3], 4); + } + } + break; -// 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); - } + // Received RWD authentication challenge and respnse + case 64: { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) { + memcpy(auth_table + auth_table_len, rx, 8); + auth_table_len += 8; + } + + // Reset the cipher state + hitag2_cipher_reset(&tag, rx); + // Check if the authentication was correct + 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]); + return; + } + // Succesful, but commented out reporting back to the Host, this may delay to much. + // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + + // Activate encryption algorithm for all further communication + tag.crypto_active = 1; + + // Use the tag password as response + memcpy(tx, tag.sectors[3], 4); + *txlen = 32; + } + break; + } + +// LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false); +// LogTrace(tx, nbytes(txlen), 0, 0, NULL, true); + + if (tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8); + } } +// sim static void hitag_reader_send_bit(int 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 field - HIGH(GPIO_SSC_DOUT); - - // 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) {}; + LED_A_ON(); + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - } else { - // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0*28) {}; - } - LED_A_OFF(); + // 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 + 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); + + if (bit == 0) { + // Zero bit: |_-| + while (AT91C_BASE_TC0->TC_CV < T0 * 22) {}; + + } else { + // One bit: |_--| + while (AT91C_BASE_TC0->TC_CV < T0 * 28) {}; + } + LED_A_OFF(); } - -static void hitag_reader_send_frame(const uint8_t* frame, size_t frame_len) -{ - // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&1); - } - // Send EOF - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - // Enable modulation, which means, drop 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); +// sim +static void hitag_reader_send_frame(const uint8_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))) & 1); + } + // Send EOF + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + // Enable modulation, which means, drop 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); } size_t blocknr; -static bool hitag2_password(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: { - // 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; - memcpy(tx,password,4); - bPwd = true; - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; - } else { - - 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); - } - - 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; -} +//----------------------------------------------------------------------------- +// 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: - *txlen = 10; - tx[0] = 0x82 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - writestate = WRITE_STATE_PAGENUM_WRITTEN; - break; - case WRITE_STATE_PAGENUM_WRITTEN: - // Check if page number was received correctly - if ((rxlen == 10) && - (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && - (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { - *txlen = 32; - memset(tx, 0, HITAG_FRAME_LEN); - memcpy(tx, writedata, 4); - writestate = WRITE_STATE_PROG; - } 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; - } - break; - case WRITE_STATE_PROG: - if (rxlen == 0) { - bSuccessful = true; - } else { - bSuccessful = false; - Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); - } - return false; - default: - DbpString("hitag2_write_page: Unknown state %d"); - bSuccessful = false; - return false; - } +static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + // Reset the transmission frame length + *txlen = 0; - 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; + // 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)); } - } else { - *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; - 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; - } - } else { - // Store the received block - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; + break; + + // Received UID, tag password + case 32: { + if (!bPwd) { + *txlen = 32; + memcpy(tx, password, 4); + bPwd = true; + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } else { + + 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); + } + + 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); + } } - if (blocknr > 7) { - DbpString("Read succesful!"); - bSuccessful = true; - return false; - } else { - *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; - } - } - - if(bCrypto) { - // We have to return now to avoid double encryption - if (!bAuthenticating) { - hitag2_cipher_transcrypt(&cipher_state, tx, *txlen/8, *txlen%8); - } - } + break; - return true; + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d", rxlen); + return false; + } + break; + } + return true; } +static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + switch (writestate) { + case WRITE_STATE_START: + *txlen = 10; + tx[0] = 0x82 | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + writestate = WRITE_STATE_PAGENUM_WRITTEN; + break; + case WRITE_STATE_PAGENUM_WRITTEN: + // Check if page number was received correctly + if ((rxlen == 10) + && (rx[0] == (0x82 | (blocknr << 3) | ((blocknr ^ 7) >> 2))) + && (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { -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 - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - DbpString("Authentication failed!"); - return false; - } - *txlen = 5; - memcpy(tx,"\xc0", nbytes(*txlen)); - } break; - - // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - *txlen = 64; - memcpy(tx, NrAr, 8); - bCrypto = true; - } else { - DbpString("Authentication succesful!"); - return true; - } - } break; - - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d", rxlen); - return false; - } break; - } - - return true; + *txlen = 32; + memset(tx, 0, HITAG_FRAME_LEN); + memcpy(tx, writedata, 4); + writestate = WRITE_STATE_PROG; + } 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; + } + break; + case WRITE_STATE_PROG: + if (rxlen == 0) { + bSuccessful = true; + } else { + bSuccessful = false; + Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); + } + return false; + default: + DbpString("hitag2_write_page: Unknown state %d"); + bSuccessful = false; + return false; + } + + 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; -static bool hitag2_test_auth_attempts(uint8_t* rx, const size_t rxlen, uint8_t* tx, size_t* txlen) { + if (bCrypto) { + hitag2_cipher_transcrypt(&cipher_state, rx, rxlen / 8, rxlen % 8); + } - // 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 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]); + if (bCrypto && !bAuthenticating && write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + } else { - // Removing failed entry from authentiations table - memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8); - auth_table_len -= 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 { + *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; + 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; + } + } else { + // Store the received block + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } + if (blocknr > 7) { + DbpString("Read succesful!"); + bSuccessful = true; + return false; + } else { + *txlen = 10; + tx[0] = 0xc0 | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + } + } + } + break; - // Return if we reached the end of the authentications table - bCrypto = false; - if (auth_table_pos == auth_table_len) { - return false; - } + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d", rxlen); + return false; + } + break; + } + } - // 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); - } - *txlen = 5; - 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); - 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]); - bCrypto = false; - if ((auth_table_pos+8) == auth_table_len) { - return false; - } - auth_table_pos += 8; - memcpy(NrAr,auth_table+auth_table_pos,8); - } - } break; - - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - - return true; + 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_read_uid(uint8_t* rx, const size_t rxlen, uint8_t* tx, size_t* txlen) { - // Reset the transmission frame length - *txlen = 0; +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 - case 0: { - // Just starting or if there is no answer - *txlen = 5; - memcpy(tx, "\xC0", nbytes(*txlen) ); - } 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("Uknown frame length: %d", rxlen); - return false; - } break; - } - return true; + // 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) { + DbpString("Authentication failed!"); + return false; + } + *txlen = 5; + memcpy(tx, "\xC0", nbytes(*txlen)); + } + break; + + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + *txlen = 64; + memcpy(tx, NrAr, 8); + bCrypto = true; + } else { + DbpString("Authentication succesful!"); + return true; + } + } + break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d", rxlen); + return false; + } + break; + } + + return true; } -void SnoopHitag(uint32_t type) { - int frame_count; - int response; - int overflow; - bool rising_edge; - bool reader_frame; - int lastbit; - bool bSkip; - int tag_sof; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); - - // Clean up trace and prepare it for storing frames - clear_trace(); - set_tracing(true); - - auth_table_len = 0; - auth_table_pos = 0; +static bool hitag2_test_auth_attempts(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: { + // 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]); + + // 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 + 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); + } + *txlen = 5; + 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); + 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]); + bCrypto = false; + if ((auth_table_pos + 8) == auth_table_len) { + return false; + } + auth_table_pos += 8; + memcpy(NrAr, auth_table + auth_table_pos, 8); + } + } + break; + + default: { + 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 + *txlen = 5; + memcpy(tx, "\xC0", nbytes(*txlen)); + } + 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("Uknown frame length: %d", rxlen); + return false; + } + break; + } + return true; +} + +// Hitag2 Sniffing +void SniffHitag(void) { + + StopTicks(); + +// int frame_count; + int response; + int overflow; + bool rising_edge; + bool reader_frame; + int lastbit; + bool bSkip; + int tag_sof; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + auth_table_len = 0; + auth_table_pos = 0; 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); - 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; + memset(auth_table, 0x00, AUTH_TABLE_LENGTH); - // 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 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on rising edge of TIOA. - 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 - 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() && !usb_poll_validate_length()) { - // 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 - 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; + DbpString("Starting Hitag2 sniffing"); + LED_D_ON(); - // Shorter periods will only happen with reader frames - if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { - // Switch from tag to reader capture - LED_C_OFF(); - reader_frame = true; - 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; - 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 (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 - } - } else { - LED_C_ON(); - // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7-(rxlen%8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7-(rxlen%8)); - rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7-(rxlen%8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7-(rxlen%8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7-(rxlen%8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - } - } - - // Check if frame was captured - if(rxlen > 0) { - frame_count++; - if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) { - DbpString("Trace full"); - break; - } + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Check if we recognize a valid authentication attempt - if (nbytes(rxlen) == 8) { - // Store the authentication attempt - if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { - memcpy(auth_table+auth_table_len,rx,8); - auth_table_len += 8; - } - } - - // Reset the received frame and response timing info - 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 { - // Save the timer overflow, will be 0 when frame was received - overflow += (AT91C_BASE_TC1->TC_CV/T0); - } - // Reset the frame length - rxlen = 0; - // Reset the timer to restart while-loop that receives frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - } - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // 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 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // 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_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; + + // Enable and reset counter + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero + + // Reset the received frame, frame count and timing info + 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() && !data_available()) { + // 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 + 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; + + // Shorter periods will only happen with reader frames + if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { + // Switch from tag to reader capture + LED_C_OFF(); + reader_frame = true; + 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; + 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 (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 + } + } else { + LED_C_ON(); + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + } + } + + // Check if frame was captured + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, reader_frame); + + // Check if we recognize a valid authentication attempt + if (nbytes(rxlen) == 8) { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) { + memcpy(auth_table + auth_table_len, rx, 8); + auth_table_len += 8; + } + } + + // Reset the received frame and response timing info + 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 { + // Save the timer overflow, will be 0 when frame was received + overflow += (AT91C_BASE_TC1->TC_CV / T0); + } + // Reset the frame length + rxlen = 0; + // Reset the timer to restart while-loop that receives frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + } + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - set_tracing(false); -// Dbprintf("frame received: %d",frame_count); -// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); -// DbpString("All done"); + + // release allocated memory from BigBuff. + BigBuf_free(); + StartTicks(); + + DbpString("Hitag2 sniffing end, use `lf hitag list` for annotations"); } -void SimulateHitagTag(bool tag_mem_supplied, uint8_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; - bool bQuitTraceFull = false; - bQuiet = false; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); +// Hitag2 simulation +void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); + StopTicks(); - // Clean up trace and prepare it for storing frames - clear_trace(); - set_tracing(true); - - auth_table_len = 0; - auth_table_pos = 0; - uint8_t* auth_table; +// int frame_count = 0; + int response = 0, overflow = 0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t tx[HITAG_FRAME_LEN]; + size_t txlen = 0; - auth_table = (uint8_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); - memset(auth_table, 0x00, AUTH_TABLE_LENGTH); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); - DbpString("Starting Hitag2 simulation"); - LED_D_ON(); - hitag2_init(); - - if (tag_mem_supplied) { - DbpString("Loading hitag2 memory..."); - memcpy((uint8_t*)tag.sectors,data,48); - } + auth_table_len = 0; + auth_table_pos = 0; + auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); + memset(auth_table, 0x00, AUTH_TABLE_LENGTH); - uint32_t block = 0; - 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); - } - - // Set up simulator mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - SpinDelay(50); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); + // Reset the received frame, frame count and timing info + memset(rx, 0x00, sizeof(rx)); - // 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; + DbpString("Starting Hitag2 simulation"); - // 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_TC1->TC_CCR = AT91C_TC_CLKDIS; + LED_D_ON(); + hitag2_init(); - // 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; + if (tag_mem_supplied) { + DbpString("Loading hitag2 memory..."); + memcpy((uint8_t *)tag.sectors, data, 48); + } - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - // 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 - int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; - overflow = 0; + uint32_t block = 0; + 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); + } - // 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 > 4) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,true)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // 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); - // Process the incoming frame (rx) and prepare the outgoing frame (tx) - 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 - // terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); + // 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; - // Send and store the tag answer (if there is any) - if (txlen) { - // Transmit the tag frame - hitag_send_frame(tx,txlen); - // Store the frame in the trace - if (!bQuiet) { - if (!LogTraceHitag(tx,txlen,0,0,false)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - // Reset the received frame and response timing info - memset(rx,0x00,sizeof(rx)); - response = 0; - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - LED_B_OFF(); - } - // Reset the frame length - 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; - } - 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); - - DbpString("Sim Stopped"); - set_tracing(false); + // 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 + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); + + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on 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; + + // Enable and reset counter + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero + + while (!BUTTON_PRESS() && !data_available()) { + // 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 + 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 > 4) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, response, NULL, true); + + // 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); + + // 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) { + hitag_send_frame(tx, txlen); + LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); + } + + // Reset the received frame and response timing info + memset(rx, 0x00, sizeof(rx)); + response = 0; + + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + LED_B_OFF(); + } + // Reset the frame length + 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; + } + + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + // release allocated memory from BigBuff. + BigBuf_free(); + + StartTicks(); + + DbpString("Sim Stopped"); } -void ReaderHitag(hitag_function htf, hitag_data* htd) { - int frame_count = 0; - int response = 0; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - uint8_t txbuf[HITAG_FRAME_LEN]; - uint8_t* tx = txbuf; - size_t txlen = 0; - int lastbit = 1; - 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 - clear_trace(); - set_tracing(true); - - //DbpString("Starting Hitag reader family"); +void ReaderHitag(hitag_function htf, hitag_data *htd) { - // 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; - } 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; + StopTicks(); - 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); - set_tracing(false); - 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); - SpinDelay(20); - - // 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(); +// int frame_count = 0; + int response = 0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; + int lastbit = 1; + bool bSkip; + int reset_sof; + int tag_sof; + int t_wait = HITAG_T_WAIT_MAX; + bool bStop = false; - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + bSuccessful = false; - // 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); + // Check configuration + switch (htf) { + case RHT2F_PASSWORD: { + Dbprintf("List identifier in password mode"); + memcpy(password, htd->pwd.password, 4); + blocknr = 0; + bPwd = false; + break; + } + case RHT2F_AUTHENTICATE: { + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr, htd->auth.NrAr, 8); + Dbhexdump(8, NrAr, false); + bCrypto = false; + bAuthenticating = false; + 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; + bCrypto = false; + bAuthenticating = false; + break; + } + case RHT2F_TEST_AUTH_ATTEMPTS: { + Dbprintf("Testing %d authentication attempts", (auth_table_len / 8)); + auth_table_pos = 0; + memcpy(NrAr, auth_table, 8); + bCrypto = false; + break; + } + case RHT2F_UID_ONLY: { + blocknr = 0; + bCrypto = false; + bAuthenticating = false; + break; + } + default: { + Dbprintf("Error, unknown function: %d", htf); + set_tracing(false); + StartTicks(); + return; + } + } - // 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_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // 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; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + BigBuf_free(); + clear_trace(); + set_tracing(true); - // 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); - set_tracing(false); - LED_D_OFF(); - return; - } - uint8_t attempt_count=0; - 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; - } - } - } - - // By default reset the transmission buffer - tx = txbuf; - 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, 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); - set_tracing(false); - LED_D_OFF(); - return; - } 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))); - - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + LED_D_ON(); + hitag2_init(); - // 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; - 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) { - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7-(rxlen%8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7-(rxlen%8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7-(rxlen%8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7-(rxlen%8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7-(rxlen%8)); - rxlen++; - } - } else { - //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; - } - } - } - 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); - set_tracing(false); + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - if ( bSuccessful ) - cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); - else - cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); + // 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; + + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); + + // Enable Peripheral Clock for + // TIMER_CLOCK0, used to measure exact timing before answering + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); + + // PIO_A - BSR + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on falling edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + + // Enable and reset counters + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero + + // Tag specific configuration settings (sof, timings, etc.) + if (htf < 10) { + // hitagS settings + reset_sof = 1; + t_wait = 200; + } else if (htf < 20) { + // hitag1 settings + reset_sof = 1; + t_wait = 200; + } else if (htf < 30) { + // hitag2 settings + reset_sof = 4; + t_wait = HITAG_T_WAIT_2; + } else { + Dbprintf("Error, unknown hitag reader type: %d", htf); + goto out; + } + uint8_t attempt_count = 0; + + while (!bStop && !BUTTON_PRESS() && !data_available()) { + + WDT_HIT(); + + // Check if frame was captured and store it + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, response, NULL, false); + } + + // By default reset the transmission buffer + tx = txbuf; + 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, 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))); + + // 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++; + LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true); + } + + // Reset values for receiving frames + memset(rx, 0x00, sizeof(rx)); + rxlen = 0; + lastbit = 1; + bSkip = true; + tag_sof = reset_sof; + response = 0; + uint32_t errorCount = 0; + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + + // Check if falling edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + 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: + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + // release allocated memory from BigBuff. + BigBuf_free(); + StartTicks(); + + if (bSuccessful) + reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48); + else + reply_old(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 tag_sof; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop; - 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(); +void WriterHitag(hitag_function htf, hitag_data *htd, int page) { - // DbpString("Starting Hitag reader family"); + StopTicks(); - // 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; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - writestate = WRITE_STATE_START; - } 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); +// int frame_count = 0; + int response = 0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; + int lastbit; + int reset_sof; + int t_wait = HITAG_T_WAIT_MAX; + bool bStop; - // 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(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + set_tracing(true); + clear_trace(); - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + // Reset the return status + bSuccessful = false; - // 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); + // 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; + bCrypto = false; + bAuthenticating = false; + writestate = WRITE_STATE_START; + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + StartTicks(); + return; + } + break; + } - // 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_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // 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; + LED_D_ON(); + hitag2_init(); - // Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; + // 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; - // 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()) { - // 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; - } - } - } - } - - // By default reset the transmission buffer - tx = txbuf; - switch(htf) { - case WHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx,rxlen,tx,&txlen, true); - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } 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"); - - // Transmit the reader frame - hitag_reader_send_frame(tx,txlen); + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); - // 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; - } - } - } - } + // Enable Peripheral Clock for + // TIMER_CLOCK0, used to measure exact timing before answering + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - // 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; + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - // 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) + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // 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) + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - // 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; - } - } - - // 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); + // TC1: 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; + + while (AT91C_BASE_TC0->TC_CV > 0) {}; + + // Reset the received frame, frame count and timing info + lastbit = 1; + bStop = false; + + // Tag specific configuration settings (sof, timings, etc.) + if (htf < 10) { + // hitagS settings + reset_sof = 1; + t_wait = 200; + } else if (htf < 20) { + // hitag1 settings + reset_sof = 1; + t_wait = 200; + } else if (htf < 30) { + // hitag2 settings + reset_sof = 4; + t_wait = HITAG_T_WAIT_2; + } else { + Dbprintf("Error, unknown hitag reader type: %d", htf); + return; + } + + while (!bStop && !BUTTON_PRESS() && !data_available()) { + + WDT_HIT(); + + // Check if frame was captured and store it + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, response, NULL, false); + } + + // By default reset the transmission buffer + tx = txbuf; + switch (htf) { + case WHT2F_CRYPTO: { + bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + 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))) {}; + + // 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++; + LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true); + } + + // Reset values for receiving frames + memset(rx, 0x00, sizeof(rx)); + rxlen = 0; + lastbit = 1; + bool bSkip = true; + int tag_sof = reset_sof; + response = 0; + uint32_t errorCount = 0; + + // 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; + } + } + + // 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)); + } + } + + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + StartTicks(); + + reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48); } diff --git a/common/iso14443crc.h b/armsrc/hitag2.h similarity index 53% rename from common/iso14443crc.h rename to armsrc/hitag2.h index 36c4be2f6..c62a2a221 100644 --- a/common/iso14443crc.h +++ b/armsrc/hitag2.h @@ -1,19 +1,23 @@ //----------------------------------------------------------------------------- +// (c) 2012 Roel Verdult +// // 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. //----------------------------------------------------------------------------- -// ISO14443 CRC calculation code. +// Hitag2 type prototyping //----------------------------------------------------------------------------- -#ifndef __ISO14443CRC_H -#define __ISO14443CRC_H -#include "common.h" +#ifndef _HITAG2_H_ +#define _HITAG2_H_ -//----------------------------------------------------------------------------- -// Routines to compute the CRCs (two different flavours, just for confusion) -// required for ISO 14443, swiped directly from the spec. +#include +#include +#include "hitag.h" -uint16_t UpdateCrc14443(uint8_t b, uint16_t *crc); +void SniffHitag(void); +void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data); +void ReaderHitag(hitag_function htf, hitag_data *htd); +void WriterHitag(hitag_function htf, hitag_data *htd, int page); #endif diff --git a/armsrc/hitag2_crypto.c b/armsrc/hitag2_crypto.c new file mode 100644 index 000000000..7d1e10d87 --- /dev/null +++ b/armsrc/hitag2_crypto.c @@ -0,0 +1,116 @@ +//----------------------------------------------------------------------------- +// 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 Crypto +// +// (c) 2009 Henryk Plötz +// (c) 2012 Roel Verdult +// (c) 2019 Iceman +//----------------------------------------------------------------------------- +#include "hitag2_crypto.h" + +/* 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. +// For educational purposes only. +// No warranties or guarantees of any kind. +// This code is released into the public domain by its author. + +// Single bit Hitag2 functions: +#ifndef i4 +#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +#endif + +static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + +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; +} + +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; +} + +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); +} + +// "MIKRON" = O N M I K R +// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key +// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear +// Random = 65 6E 45 72 - Random IV, transmitted in clear +//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream + +// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6". +// The inverse of the first 4 bytes is sent to the tag to authenticate. +// The rest is encrypted by XORing it with the subsequent keystream. + +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; +} + +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); + 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_)); +} + +int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) { + uint8_t authenticator_should[4]; + authenticator_should[0] = ~_hitag2_byte(cs); + authenticator_should[1] = ~_hitag2_byte(cs); + authenticator_should[2] = ~_hitag2_byte(cs); + authenticator_should[3] = ~_hitag2_byte(cs); + return (memcmp(authenticator_should, authenticator_is, 4) == 0); +} + +int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t 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); + return 0; +} + diff --git a/armsrc/hitag2_crypto.h b/armsrc/hitag2_crypto.h new file mode 100644 index 000000000..d874955e0 --- /dev/null +++ b/armsrc/hitag2_crypto.h @@ -0,0 +1,36 @@ +#ifndef __HITAG2_CRYPTO_H +#define __HITAG2_CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "string.h" +#include "util.h" + +struct hitag2_tag { + uint32_t uid; + enum { + TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr + TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password + TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands + TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written + } state; + uint16_t active_sector; + uint8_t crypto_active; + uint64_t cs; + uint8_t sectors[12][4]; +}; + +uint32_t _f20(const uint64_t x); +uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV); +uint64_t _hitag2_round(uint64_t *state); +uint32_t _hitag2_byte(uint64_t *x); +void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv); +int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is); +int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ; +#ifdef __cplusplus +} +#endif + +#endif diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 59e2694e5..d52e18fd4 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -10,133 +10,70 @@ //----------------------------------------------------------------------------- // Some code was copied from Hitag2.c //----------------------------------------------------------------------------- -#include -#include "proxmark3.h" -#include "apps.h" -#include "util.h" + #include "hitagS.h" -#include "hitag2.h" -#include "string.h" -#include "BigBuf.h" #define CRC_PRESET 0xFF #define CRC_POLYNOM 0x1D -#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))) - static bool bQuiet; static bool bSuccessful; static struct hitagS_tag tag; -static byte_t page_to_be_written = 0; +static uint8_t page_to_be_written = 0; static int block_data_left = 0; + typedef enum modulation { - AC2K = 0, - AC4K, - MC4K, - MC8K + AC2K = 0, + AC4K, + MC4K, + MC8K } MOD; -static MOD m = AC2K; //used modulation + +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; +static int sof_bits; // number of start-of-frame bits +static uint8_t pwdh0, pwdl0, pwdl1; // password bytes +static uint32_t rnd = 0x74124485; // randomnumber size_t blocknr; -bool end=false; +bool end = false; +//#define SENDBIT_TEST -// Single bit Hitag2 functions: -#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 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 -#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 u32 - -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; - - return (ht2_f5c >> i5) & 1; -} -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); - - *state = x; - return f20(x); -} -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++) { - x >>= 1; - x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; - } - return x; -} -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; -} +#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)))) // 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 +#ifndef T0 +#define T0 192 +#endif -#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_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_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 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 @@ -144,1018 +81,1035 @@ static u32 hitag2_byte(u64 *x) { * 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); +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; + 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; - } + 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_send_frame(const byte_t* frame, size_t frame_len) { -// Send start of frame +static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { + // SOF - send start of frame + for (size_t i = 0; i < sof_bits; i++) { + hitag_send_bit(1); + } - 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); + } -// 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); + 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 + LED_A_ON(); + // Reset clock for the next bit + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; -// 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); + // 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 - // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); + HIGH(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); +#ifdef SENDBIT_TEST + // 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); + 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); - } - } + if (bit == 0) { + // Zero bit: |_-| + while (AT91C_BASE_TC0->TC_CV < T0 * 11) {}; + } else { + // One bit: |_--| + while (AT91C_BASE_TC0->TC_CV < T0 * 14) {}; + } +#else + // Wait for 4-10 times the carrier period + while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; - LED_A_OFF(); + LOW(GPIO_SSC_DOUT); + + if (bit == 0) { + // Zero bit: |_-| + while (AT91C_BASE_TC0->TC_CV < T0 * 22) {}; + } else { + // One bit: |_--| + while (AT91C_BASE_TC0->TC_CV < T0 * 28) {}; + } +#endif + + 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_reader_send_frame(const uint8_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; + + HIGH(GPIO_SSC_DOUT); + + // Wait for 4-10 times the carrier period + while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; + + LOW(GPIO_SSC_DOUT); } /* * 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; +static int check_select(uint8_t *rx, uint32_t uid) { + unsigned char resp[48]; + uint32_t ans = 0x0; + for (int i = 0; i < 48; i++) + resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1; + for (int i = 0; i < 32; i++) + ans += resp[5 + i] << (31 - i); + + 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; - u64 state; - unsigned char crc; +static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, + uint8_t *tx, size_t *txlen) { + uint8_t rx_air[HITAG_FRAME_LEN]; + 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 = HT_READY; - tag.tstate = HT_NO_OP; - if ((rx[0] & 0xf0) == 0x30) { - tag.mode = HT_STANDARD; - sof_bits = 1; - m = AC2K; - } - if ((rx[0] & 0xf0) == 0xc0) { - tag.mode = HT_ADVANCED; - sof_bits = 3; - m = AC2K; - } + // Copy the (original) received frame how it is send over the air + memcpy(rx_air, rx, nbytes(rxlen)); - if ((rx[0] & 0xf0) == 0xd0) { - tag.mode = HT_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 HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + // Reset the transmission frame length + *txlen = 0; - //send configuration - for (i = 0; i < 4; i++) - tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; - tx[3] = 0xff; - if (tag.mode != HT_STANDARD) { - *txlen = 40; - crc = CRC_PRESET; - for (i = 0; i < 4; i++) - calc_crc(&crc, tx[i], 8); - tx[4] = crc; - } - } - } - break; - case 64: { - //challenge message received - Dbprintf("Challenge for UID: %X", temp_uid); - temp2++; - *txlen = 32; - 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]); - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + // 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 = HT_READY; + tag.tstate = HT_NO_OP; + if ((rx[0] & 0xf0) == 0x30) { + tag.mode = HT_STANDARD; + sof_bits = 1; + m = AC2K; + } + if ((rx[0] & 0xf0) == 0xc0) { + tag.mode = HT_ADVANCED; + sof_bits = 3; + m = AC2K; + } - for (i = 0; i < 4; i++) - hitag2_byte(&state); - //send con2,pwdh0,pwdl0,pwdl1 encrypted as a response - tx[0] = hitag2_byte(&state) ^ ((tag.pages[0][1] >> 16) & 0xff); - tx[1] = hitag2_byte(&state) ^ tag.pwdh0; - tx[2] = hitag2_byte(&state) ^ tag.pwdl0; - tx[3] = hitag2_byte(&state) ^ tag.pwdl1; - if (tag.mode != HT_STANDARD) { - //add crc8 - *txlen = 40; - crc = CRC_PRESET; - calc_crc(&crc, ((tag.pages[0][1] >> 16) & 0xff), 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)); - } - /* - * some readers do not allow to authenticate multiple times in a row with the same tag. - * use this to change the uid between authentications. - */ + if ((rx[0] & 0xf0) == 0xd0) { + tag.mode = HT_FAST_ADVANCED; + sof_bits = 3; + m = AC4K; + } + //send uid as a response + *txlen = 32; + for (int 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 HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } - /* - if (temp2 % 2 == 0) { - tag.uid = 0x11223344; - tag.pages[0][0] = 0x44332211; - } else { - tag.uid = 0x55667788; - tag.pages[0][0] = 0x88776655; - } - */ - } - case 40: - //data received to be written - if (tag.tstate == HT_WRITING_PAGE_DATA) { - tag.tstate = HT_NO_OP; - tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] - << 0) + (rx[1] << 8) + (rx[2] << 16) + (rx[3] << 24); - //send ack - *txlen = 2; - tx[0] = 0x40; - page_to_be_written = 0; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - } else if (tag.tstate == HT_WRITING_BLOCK_DATA) { - tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] - << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; - //send ack - *txlen = 2; - tx[0] = 0x40; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - page_to_be_written++; - block_data_left--; - if (block_data_left == 0) { - tag.tstate = HT_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); - *txlen = 32; - tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; - if (tag.LKP && page == 1) - tx[3] = 0xff; + //send configuration + for (int i = 0; i < 4; i++) + tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; + tx[3] = 0xff; + if (tag.mode != HT_STANDARD) { + *txlen = 40; + crc = CRC_PRESET; + for (int i = 0; i < 4; i++) + calc_crc(&crc, tx[i], 8); + tx[4] = crc; + } + } + } + break; + case 64: { + //challenge message received + Dbprintf("Challenge for UID: %X", temp_uid); + temp2++; + *txlen = 32; + 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]); - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } - if (tag.mode != HT_STANDARD) { - //add crc8 - *txlen = 40; - crc = CRC_PRESET; - for (i = 0; i < 4; i++) - calc_crc(&crc, tx[i], 8); - tx[4] = crc; - } + for (int i = 0; i < 4; i++) + _hitag2_byte(&state); - 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); - *txlen = 32 * 4; - //send page,...,page+3 data - for (i = 0; i < 4; i++) { - tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; - page++; - } + //send con2, pwdh0, pwdl0, pwdl1 encrypted as a response + tx[0] = _hitag2_byte(&state) ^ ((tag.pages[0][1] >> 16) & 0xff); + tx[1] = _hitag2_byte(&state) ^ tag.pwdh0; + tx[2] = _hitag2_byte(&state) ^ tag.pwdl0; + tx[3] = _hitag2_byte(&state) ^ tag.pwdl1; + if (tag.mode != HT_STANDARD) { + //add crc8 + *txlen = 40; + crc = CRC_PRESET; + calc_crc(&crc, ((tag.pages[0][1] >> 16) & 0xff), 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)); + } + /* + * some readers do not allow to authenticate multiple times in a row with the same tag. + * use this to change the uid between authentications. - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + if (temp2 % 2 == 0) { + tag.uid = 0x11223344; + tag.pages[0][0] = 0x44332211; + } else { + tag.uid = 0x55667788; + tag.pages[0][0] = 0x88776655; + } + */ + } + case 40: + //data received to be written + if (tag.tstate == HT_WRITING_PAGE_DATA) { + tag.tstate = HT_NO_OP; + tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] + << 0) + (rx[1] << 8) + (rx[2] << 16) + (rx[3] << 24); + //send ack + *txlen = 2; + tx[0] = 0x40; + page_to_be_written = 0; + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + } else if (tag.tstate == HT_WRITING_BLOCK_DATA) { + tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] + << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; + //send ack + *txlen = 2; + tx[0] = 0x40; + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + page_to_be_written++; + block_data_left--; + if (block_data_left == 0) { + tag.tstate = HT_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 + uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + *txlen = 32; + tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; + tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; + tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; + tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + if (tag.LKP && page == 1) + tx[3] = 0xff; - if (tag.mode != HT_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; - } + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } - if ((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); + if (tag.mode != HT_STANDARD) { + //add crc8 + *txlen = 40; + crc = CRC_PRESET; + for (int i = 0; i < 4; i++) + calc_crc(&crc, tx[i], 8); + tx[4] = crc; + } - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - if ((tag.LCON && page == 1) - || (tag.LKP && (page == 2 || page == 3))) { - //deny - *txlen = 0; - } else { - //allow - *txlen = 2; - tx[0] = 0x40; - page_to_be_written = page; - tag.tstate = HT_WRITING_PAGE_DATA; - } + 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 + uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + *txlen = 32 * 4; + //send page,...,page+3 data + for (int i = 0; i < 4; i++) { + tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; + tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; + tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; + tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + page++; + } - } else if ((rx[0] & 0xf0) == 0x90) //write block - { - page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - 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 = HT_WRITING_BLOCK_DATA; - } - } - } - break; - default: + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } - break; - } + if (tag.mode != HT_STANDARD) { + //add crc8 + *txlen = 32 * 4 + 8; + crc = CRC_PRESET; + for (int 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 + uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + if ((tag.LCON && page == 1) + || (tag.LKP && (page == 2 || page == 3))) { + //deny + *txlen = 0; + } else { + //allow + *txlen = 2; + tx[0] = 0x40; + page_to_be_written = page; + tag.tstate = HT_WRITING_PAGE_DATA; + } + + } else if ((rx[0] & 0xf0) == 0x90) { //write block + uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + 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 = HT_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]; - 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; - u64 state; - byte_t auth_ks[4]; - byte_t conf_pages[3]; - memcpy(rx_air, rx, nbytes(rxlen)); - *txlen = 0; +static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrAr, uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + uint8_t rx_air[HITAG_FRAME_LEN]; + int response_bit[200]; + unsigned char mask = 1; + unsigned char uid[32]; + unsigned char crc; + uint64_t state; + uint8_t auth_ks[4]; + uint8_t conf_pages[3]; + memcpy(rx_air, rx, nbytes(rxlen)); + *txlen = 0; - if (tag.pstate == HT_READY && rxlen >= 67) { - //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++; - } - } - k = 0; - for (i = 5; i < z; i += 2) { - uid[k] = response_bit[i]; - k++; - if (k > 31) - break; - } - 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]; - if (DEBUG) - Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); - tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); + if (tag.pstate == HT_READY && rxlen >= 67) { + //received uid + if (end == true) { + Dbprintf("authentication failed!"); + return -1; + } + int z = 0; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + uint16_t k = 0; + for (int i = 5; i < z; i += 2) { + uid[k] = response_bit[i]; + k++; + if (k > 31) + break; + } + uint8_t uid1 = (uid[0] << 7) + | (uid[1] << 6) + | (uid[2] << 5) + | (uid[3] << 4) + | (uid[4] << 3) + | (uid[5] << 2) + | (uid[6] << 1) + | uid[7]; - //select uid - *txlen = 45; - 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); - 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 = HT_INIT; - } else if (tag.pstate == HT_INIT && rxlen == 44) { - // received configuration after select command - 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++; - } - } - conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6) - | (response_bit[6] << 5) | (response_bit[7] << 4) - | (response_bit[8] << 3) | (response_bit[9] << 2) - | (response_bit[10] << 1) | response_bit[11]); - //check wich memorysize this tag has - if (response_bit[10] == 0 && response_bit[11] == 0) - tag.max_page = 32 / 32; - if (response_bit[10] == 0 && response_bit[11] == 1) - tag.max_page = 256 / 32; - if (response_bit[10] == 1 && response_bit[11] == 0) - tag.max_page = 2048 / 32; - conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6) - | (response_bit[14] << 5) | (response_bit[15] << 4) - | (response_bit[16] << 3) | (response_bit[17] << 2) - | (response_bit[18] << 1) | response_bit[19]); - tag.auth = response_bit[12]; - tag.TTFC = response_bit[13]; - //tag.TTFDR in response_bit[14] and response_bit[15] - //tag.TTFM in response_bit[16] and response_bit[17] - tag.LCON = response_bit[18]; - tag.LKP = response_bit[19]; - conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6) - | (response_bit[22] << 5) | (response_bit[23] << 4) - | (response_bit[24] << 3) | (response_bit[25] << 2) - | (response_bit[26] << 1) | response_bit[27]); - tag.LCK7 = response_bit[20]; - tag.LCK6 = response_bit[21]; - tag.LCK5 = response_bit[22]; - tag.LCK4 = response_bit[23]; - tag.LCK3 = response_bit[24]; - tag.LCK2 = response_bit[25]; - tag.LCK1 = response_bit[26]; - tag.LCK0 = response_bit[27]; + uint8_t uid2 = (uid[8] << 7) + | (uid[9] << 6) + | (uid[10] << 5) + | (uid[11] << 4) + | (uid[12] << 3) + | (uid[13] << 2) + | (uid[14] << 1) + | uid[15]; - if (DEBUG) - Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], - conf_pages[1], conf_pages[2]); - 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)); + uint8_t uid3 = (uid[16] << 7) + | (uid[17] << 6) + | (uid[18] << 5) + | (uid[19] << 4) + | (uid[20] << 3) + | (uid[21] << 2) + | (uid[22] << 1) + | uid[23]; - 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; + uint8_t uid4 = (uid[24] << 7) + | (uid[25] << 6) + | (uid[26] << 5) + | (uid[27] << 4) + | (uid[28] << 3) + | (uid[29] << 2) + | (uid[30] << 1) + | uid[31]; - 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 = HT_AUTHENTICATE; - } else { - Dbprintf("authentication failed!"); - return -1; - } - } else if (tag.auth == 0) { - tag.pstate = HT_SELECTED; - } - - } else if (tag.pstate == HT_AUTHENTICATE && rxlen == 44) { - //encrypted con2,password received. - crc = CRC_PRESET; - calc_crc(&crc, 0x80, 1); - calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); - if (DEBUG) { - Dbprintf("UID:::%X", tag.uid); - Dbprintf("RND:::%X", rnd); - } + if (DEBUG) + Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); - //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); - } + tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); - if (DEBUG) - Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); - + //select uid + *txlen = 45; + 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); + + for (int i = 0; i < 100; i++) { + response_bit[i] = 0; + } + + for (int i = 0; i < 5; i++) { + response_bit[i] = 0; + } + { + int i = 5; + for (; i < 37; i++) { + response_bit[i] = uid[i - 5]; + } + + for (int j = 0; j < 8; j++) { + response_bit[i] = 0; + if ((crc & ((mask << 7) >> j)) != 0) + response_bit[i] = 1; + i++; + } + } + k = 0; + for (int 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 = HT_INIT; + } else if (tag.pstate == HT_INIT && rxlen == 44) { + // received configuration after select command + int z = 0; + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6) + | (response_bit[6] << 5) | (response_bit[7] << 4) + | (response_bit[8] << 3) | (response_bit[9] << 2) + | (response_bit[10] << 1) | response_bit[11]); + //check wich memorysize this tag has + if (response_bit[10] == 0 && response_bit[11] == 0) + tag.max_page = 32 / 32; + if (response_bit[10] == 0 && response_bit[11] == 1) + tag.max_page = 256 / 32; + if (response_bit[10] == 1 && response_bit[11] == 0) + tag.max_page = 2048 / 32; + conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6) + | (response_bit[14] << 5) | (response_bit[15] << 4) + | (response_bit[16] << 3) | (response_bit[17] << 2) + | (response_bit[18] << 1) | response_bit[19]); + tag.auth = response_bit[12]; + tag.TTFC = response_bit[13]; + //tag.TTFDR in response_bit[14] and response_bit[15] + //tag.TTFM in response_bit[16] and response_bit[17] + tag.LCON = response_bit[18]; + tag.LKP = response_bit[19]; + conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6) + | (response_bit[22] << 5) | (response_bit[23] << 4) + | (response_bit[24] << 3) | (response_bit[25] << 2) + | (response_bit[26] << 1) | response_bit[27]); + tag.LCK7 = response_bit[20]; + tag.LCK6 = response_bit[21]; + tag.LCK5 = response_bit[22]; + tag.LCK4 = response_bit[23]; + tag.LCK3 = response_bit[24]; + tag.LCK2 = response_bit[25]; + tag.LCK1 = response_bit[26]; + tag.LCK0 = response_bit[27]; + + if (DEBUG) + Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); + + 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)); + + for (int 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 (int i = 0; i < 8; i++) + tx[i] = ((NrAr >> (56 - (i * 8))) & 0xff); + } + end = true; + tag.pstate = HT_AUTHENTICATE; + } else { + Dbprintf("authentication failed!"); + return -1; + } + } else if (tag.auth == 0) { + tag.pstate = HT_SELECTED; + } + + } else if (tag.pstate == HT_AUTHENTICATE && rxlen == 44) { + //encrypted con2,password received. + crc = CRC_PRESET; + calc_crc(&crc, 0x80, 1); + calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); + calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); + 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 (int 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); + + //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); + //rnd += 1; + } + tag.pstate = HT_SELECTED; //tag is now ready for read/write commands + } + return 0; - //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); - //rnd += 1; - } - tag.pstate = HT_SELECTED; //tag is now ready for read/write commands - } - 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; - //bool bQuitTraceFull = false; - bQuiet = false; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen = 0; - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); +void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); + StopTicks(); - DbpString("Starting HitagS simulation"); - LED_D_ON(); +// int frame_count = 0; + int response = 0, overflow = 0; + int i, j; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + bQuiet = false; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; - tag.pstate = HT_READY; - tag.tstate = HT_NO_OP; - for (i = 0; i < 16; i++) - for (j = 0; j < 4; j++) - tag.pages[i][j] = 0x0; - //read tag data into memory - if (tag_mem_supplied) { - DbpString("Loading hitagS memory..."); - memcpy((byte_t*)tag.pages,data,4*64); - } - tag.uid=(uint32_t)tag.pages[0]; - Dbprintf("Hitag S simulation started"); - 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]; - //con0 - tag.max_page=64; - if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==1) - tag.max_page=8; - if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==0) - tag.max_page=0; - //con1 - tag.auth=0; - if((tag.pages[1][2]&0x80) == 0x80) - tag.auth=1; - tag.LCON=0; - if((tag.pages[1][2]&0x2) == 0x02) - tag.LCON=1; - tag.LKP=0; - if((tag.pages[1][2]&0x1) == 0x01) - tag.LKP=1; - //con2 - //0=read write 1=read only - tag.LCK7=0; - if((tag.pages[1][1]&0x80) == 0x80) - tag.LCK7=1; - tag.LCK6=0; - if((tag.pages[1][1]&0x40) == 0x040) - tag.LCK6=1; - tag.LCK5=0; - if((tag.pages[1][1]&0x20) == 0x20) - tag.LCK5=1; - tag.LCK4=0; - if((tag.pages[1][1]&0x10) == 0x10) - tag.LCK4=1; - tag.LCK3=0; - if((tag.pages[1][1]&0x8) == 0x08) - tag.LCK3=1; - tag.LCK2=0; - if((tag.pages[1][1]&0x4) == 0x04) - tag.LCK2=1; - tag.LCK1=0; - if((tag.pages[1][1]&0x2) == 0x02) - tag.LCK1=1; - tag.LCK0=0; - if((tag.pages[1][1]&0x1) == 0x01) - tag.LCK0=1; + // Reset the received frame, frame count and timing info + memset(rx, 0x00, sizeof(rx)); -// 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); - SpinDelay(20); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); + // free eventually allocated BigBuf memory + BigBuf_free(); + BigBuf_Clear_ext(false); -// 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; + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); -// Disable modulation at default, which means release resistance - LOW(GPIO_SSC_DOUT); + DbpString("Starting HitagS simulation"); + LED_D_ON(); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + tag.pstate = HT_READY; + tag.tstate = HT_NO_OP; -// 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; + for (i = 0; i < 16; i++) + for (j = 0; j < 4; j++) + tag.pages[i][j] = 0x0; -// Disable timer during configuration - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // read tag data into memory + if (tag_mem_supplied) { + DbpString("Loading hitagS memory..."); + memcpy((uint8_t *)tag.pages, data, 4 * 64); + } -// 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; + tag.uid = (uint32_t)tag.pages[0]; + 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]; + //con0 + tag.max_page = 64; + if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 1) + tag.max_page = 8; + if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) + tag.max_page = 0; + //con1 + tag.auth = 0; + if ((tag.pages[1][2] & 0x80) == 0x80) + tag.auth = 1; + tag.LCON = 0; + if ((tag.pages[1][2] & 0x2) == 0x02) + tag.LCON = 1; + tag.LKP = 0; + if ((tag.pages[1][2] & 0x1) == 0x01) + tag.LKP = 1; + //con2 + //0=read write 1=read only + tag.LCK7 = 0; + if ((tag.pages[1][1] & 0x80) == 0x80) + tag.LCK7 = 1; + tag.LCK6 = 0; + if ((tag.pages[1][1] & 0x40) == 0x040) + tag.LCK6 = 1; + tag.LCK5 = 0; + if ((tag.pages[1][1] & 0x20) == 0x20) + tag.LCK5 = 1; + tag.LCK4 = 0; + if ((tag.pages[1][1] & 0x10) == 0x10) + tag.LCK4 = 1; + tag.LCK3 = 0; + if ((tag.pages[1][1] & 0x8) == 0x08) + tag.LCK3 = 1; + tag.LCK2 = 0; + if ((tag.pages[1][1] & 0x4) == 0x04) + tag.LCK2 = 1; + tag.LCK1 = 0; + if ((tag.pages[1][1] & 0x2) == 0x02) + tag.LCK1 = 1; + tag.LCK0 = 0; + if ((tag.pages[1][1] & 0x1) == 0x01) + tag.LCK0 = 1; -// Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - frame_count = 0; - response = 0; - overflow = 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); -// Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // 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; - while (!BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); + // Disable modulation at default, which means release resistance + LOW(GPIO_SSC_DOUT); - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0) + overflow; - overflow = 0; + // Enable Peripheral Clock for + // TIMER_CLOCK0, used to measure exact timing before answering + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - // 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_PIOA->PIO_BSR = GPIO_SSC_FRAME; - LED_B_ON(); + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // 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 - } - } - } + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - // Check if frame was captured - if (rxlen > 0) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, true)) { - DbpString("Trace full"); - clear_trace(); - } - } + // 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; - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // Enable and reset counter + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitagS_handle_reader_command(rx, rxlen, tx, &txlen); + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero - // 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)) - ; + while (!BUTTON_PRESS() && !data_available()) { - // Send and store the tag answer (if there is any) - if (txlen > 0) { - // Transmit the tag frame - hitag_send_frame(tx, txlen); - // Store the frame in the trace - if (!bQuiet) { - if (!LogTraceHitag(tx, txlen, 0, 0, false)) { - DbpString("Trace full"); - clear_trace(); - } - } - } + WDT_HIT(); - // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); - response = 0; + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { + // Check if rising edge in modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0) + overflow; + overflow = 0; - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - LED_B_OFF(); - } - // Reset the frame length - 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; - } - 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); + // 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++; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, true); + + // 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_send_frame(tx, txlen); + LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); + } + + // Reset the received frame and response timing info + memset(rx, 0x00, sizeof(rx)); + response = 0; + + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + LED_B_OFF(); + } + // Reset the frame length + 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; + } + + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + // release allocated memory from BigBuff. + BigBuf_free(); + + StartTicks(); + + DbpString("Sim Stopped"); } /* @@ -1163,652 +1117,622 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { * If the key was given the password will be decrypted. * Reads every page of a hitag S transpoder. */ -void ReadHitagS(hitag_function htf, hitag_data* htd) { - int i, j, z, k; - int frame_count; - int response_bit[200]; - 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; - bool bSkip; - int reset_sof; - int tag_sof; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop = false; - bool bQuitTraceFull = false; - int sendNum = 0; - unsigned char mask = 1; - unsigned char crc; - unsigned char pageData[32]; - 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: { //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: { //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; - } +void ReadHitagS(hitag_function htf, hitag_data *htd) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; + StopTicks(); - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); + int i, j, z, k; +// int frame_count = 0; + int response = 0; + int response_bit[200]; + 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 = 1; + int reset_sof = 1; + int t_wait = HITAG_T_WAIT_MAX; + bool bStop = false; + int sendNum = 0; + unsigned char mask = 1; + unsigned char crc; + unsigned char pageData[32]; + page_to_be_written = 0; - bQuiet = false; - bQuitTraceFull = true; + //read given key/challenge + uint8_t NrAr_[8]; + uint64_t key = 0; + uint64_t NrAr = 0; + uint8_t key_[6]; - LED_D_ON(); + switch (htf) { + case RHTSF_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 RHTSF_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; + } + } - // 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; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + // Reset the return status + bSuccessful = false; - // 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); + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); - // 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(); + bQuiet = false; - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + LED_D_ON(); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + // 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; - // 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 modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); - // Disable timer during configuration - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // Enable Peripheral Clock for + // TIMER_CLOCK0, used to measure exact timing before answering + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - // 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; + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - // 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; + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - reset_sof = 1; - t_wait = 200; + // TC1: 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; - while (!bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); + // 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; - // 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; - } - } - } - } + // synchronized startup procedure + while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero - // By default reset the transmission buffer - tx = txbuf; - txlen = 0; + // Reset the received frame, frame count and timing info + t_wait = 200; - if (rxlen == 0) { - //start authentication - txlen = 5; - memcpy(tx, "\xc0", nbytes(txlen)); - tag.pstate = HT_READY; - tag.tstate = HT_NO_OP; - } else if (tag.pstate != HT_SELECTED) { - if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1) - bStop = !false; - } - if (tag.pstate == HT_SELECTED && tag.tstate == HT_NO_OP && rxlen > 0) { - //send read request - tag.tstate = HT_READING_PAGE; - txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - } else if (tag.pstate == HT_SELECTED && tag.tstate == HT_READING_PAGE - && rxlen > 0) { - //save received data - z = 0; - for (i = 0; i < 5; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) - response_bit[z] = 1; - z++; - } - } - k = 0; - for (i = 4; i < 36; i++) { - pageData[k] = response_bit[i]; - k++; - } - for (i = 0; i < 4; i++) - tag.pages[sendNum / 4][sendNum % 4] = 0x0; - for (i = 0; i < 4; i++) { - tag.pages[sendNum / 4][sendNum % 4] += ((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)]) - << (i * 8); - } - if (tag.auth && tag.LKP && sendNum == 1) { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); - } else { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, - (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); - } + while (!bStop && !BUTTON_PRESS() && !data_available()) { - sendNum++; - //display key and password if possible - if (sendNum == 2 && 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]: __ __ __ __"); - } - } + WDT_HIT(); - txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - if (sendNum >= tag.max_page) { - bStop = !false; - } - } + // Check if frame was captured and store it + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, 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; + // By default reset the transmission buffer + tx = txbuf; + txlen = 0; - // 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 + if (rxlen == 0) { + //start authentication + txlen = 5; + memcpy(tx, "\xC0", nbytes(txlen)); + tag.pstate = HT_READY; + tag.tstate = HT_NO_OP; + } else if (tag.pstate != HT_SELECTED) { + if (hitagS_handle_tag_auth(htf, key, NrAr, rx, rxlen, tx, &txlen) == -1) + bStop = !false; + } - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {}; + if (tag.pstate == HT_SELECTED && tag.tstate == HT_NO_OP && rxlen > 0) { + //send read request + tag.tstate = HT_READING_PAGE; + txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + (sendNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); + tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + } else if (tag.pstate == HT_SELECTED + && tag.tstate == HT_READING_PAGE + && rxlen > 0) { + //save received data + z = 0; + for (i = 0; i < 5; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + k = 0; + for (i = 4; i < 36; i++) { + pageData[k] = response_bit[i]; + k++; + } + for (i = 0; i < 4; i++) + tag.pages[sendNum / 4][sendNum % 4] = 0x0; + for (i = 0; i < 4; i++) { + tag.pages[sendNum / 4][sendNum % 4] += ((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)]) + << (i * 8); + } + if (tag.auth && tag.LKP && sendNum == 1) { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, + (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, + tag.pages[sendNum / 4][sendNum % 4] & 0xff); + } else { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, + (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, + (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, + tag.pages[sendNum / 4][sendNum % 4] & 0xff); + } - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + sendNum++; + //display key and password if possible + if (sendNum == 2 && tag.auth == 1 && tag.LKP) { + if (htf == RHTSF_KEY) { + Dbprintf("Page[ 2]: %02X %02X %02X %02X", + (uint8_t)(key >> 8) & 0xff, + (uint8_t) key & 0xff, + pwdl1, + pwdl0 + ); + Dbprintf("Page[ 3]: %02X %02X %02X %02X", + (uint8_t)(key >> 40) & 0xff, + (uint8_t)(key >> 32) & 0xff, + (uint8_t)(key >> 24) & 0xff, + (uint8_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]: __ __ __ __"); + } + } - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + (sendNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); + tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + if (sendNum >= tag.max_page) { + bStop = !false; + } + } - // 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; - } - } - } - } + // 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; - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - response = 0; + // 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 - // 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); + while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {}; - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + // Transmit the reader frame + hitag_reader_send_frame(tx, txlen); - LED_B_ON(); + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } + // Add transmitted frame to total count + if (txlen > 0) { +// frame_count++; + LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); + } - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } - } - end = false; - 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); + // Reset values for receiving frames + memset(rx, 0x00, sizeof(rx)); + rxlen = 0; + lastbit = 1; + bool bSkip = true; + int tag_sof = reset_sof; + response = 0; + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + // Check if falling edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { + if (rxlen > 0) + break; + } + } + } + end = false; + + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + StartTicks(); + + reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } /* * 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; - bool bSkip; - int reset_sof; - int tag_sof; - 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; - } +void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { - 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; + StopTicks(); - tag.pstate = HT_READY; - tag.tstate = HT_NO_OP; +// int frame_count = 0; + int response = 0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; + int lastbit; + int reset_sof; + int t_wait = HITAG_T_WAIT_MAX; + bool bStop; + unsigned char crc; + uint8_t data[4] = {0, 0, 0, 0}; -// Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - bQuiet = false; - bQuitTraceFull = true; + bSuccessful = false; - LED_D_ON(); + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); -// 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; + //read given key/challenge, the page and the data + uint8_t NrAr_[8]; + uint64_t key = 0; + uint64_t NrAr = 0; + uint8_t key_[6]; + switch (htf) { + case WHTSF_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; + } -// 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); + case WHTSF_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; + } + } -// 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(); + Dbprintf("Page: %d", page); + Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]); -// Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + tag.pstate = HT_READY; + tag.tstate = HT_NO_OP; -// Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); + LED_D_ON(); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + // 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; -// 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; + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); -// Disable timer during configuration - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + // Disable modulation at default, which means enable the field + LOW(GPIO_SSC_DOUT); -// 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 Peripheral Clock for + // TIMER_CLOCK0, used to measure exact timing before answering + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); -// 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; + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - reset_sof = 1; - t_wait = 200; + // 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; - while (!bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); + // 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; - // 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; - } - } - } - } + while (AT91C_BASE_TC0->TC_CV > 0); - //check for valid input - if (page == 0) { - Dbprintf( - "usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); - bStop = !false; - } + // Reset the received frame, frame count and timing info + lastbit = 1; + bStop = false; + reset_sof = 1; + t_wait = 200; - // By default reset the transmission buffer - tx = txbuf; - txlen = 0; + while (!bStop && !BUTTON_PRESS() && !data_available()) { - if (rxlen == 0 && tag.tstate == HT_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 != HT_WRITING_PAGE_DATA) { - //start the authetication - txlen = 5; - memcpy(tx, "\xc0", nbytes(txlen)); - tag.pstate = HT_READY; - tag.tstate = HT_NO_OP; - } else if (tag.pstate != HT_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; - } - if (tag.pstate == HT_SELECTED && tag.tstate == HT_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 = HT_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 == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_ACK - && rxlen == 6 && rx[0] == 0xf4) { - //ACK recieved to write the page. send data - tag.tstate = HT_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 == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_DATA - && rxlen == 6 && rx[0] == 0xf4) { - //received ACK - Dbprintf("Successful!"); - bStop = !false; - } + WDT_HIT(); - // 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; + // Check if frame was captured and store it + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, false); + } - // 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 + //check for valid input + if (page == 0) { + Dbprintf( + "usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); + bStop = !false; + } - while (AT91C_BASE_TC0->TC_CV - < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) - ; + // By default reset the transmission buffer + tx = txbuf; + txlen = 0; - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + if (rxlen == 0 && tag.tstate == HT_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 != HT_WRITING_PAGE_DATA) { + //start the authetication + txlen = 5; + memcpy(tx, "\xc0", nbytes(txlen)); + tag.pstate = HT_READY; + tag.tstate = HT_NO_OP; + } else if (tag.pstate != HT_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; + } + if (tag.pstate == HT_SELECTED && tag.tstate == HT_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 = HT_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 == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_ACK + && rxlen == 6 && rx[0] == 0xf4) { + //ACK recieved to write the page. send data + tag.tstate = HT_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 == HT_SELECTED && tag.tstate == HT_WRITING_PAGE_DATA + && rxlen == 6 && rx[0] == 0xf4) { + //received ACK + Dbprintf("Successful!"); + bStop = !false; + } - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // 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; - // 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; - } - } - } - } + // 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 - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - response = 0; + while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {}; - // 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); + // Transmit the reader frame + hitag_reader_send_frame(tx, txlen); - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - LED_B_ON(); + // Add transmitted frame to total count + if (txlen > 0) { +// frame_count++; + LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); + } - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } + // Reset values for receiving frames + memset(rx, 0x00, sizeof(rx)); + rxlen = 0; + lastbit = 1; + bool bSkip = true; + int tag_sof = reset_sof; + response = 0; + uint32_t errorCount = 0; - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } - } - end=false; - 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); + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + // Check if falling edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + errorCount++; + } + } + + // if we saw over 100 wierd values break it probably isn't hitag... + if (errorCount > 100) break; + + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { + if (rxlen > 0) + break; + } + } + } + end = false; + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + StartTicks(); + + reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } /* @@ -1818,328 +1742,301 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { * is not received correctly due to Antenna problems. This function * detects these challenges. */ -void check_challenges(bool file_given, byte_t* data) { - 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; - bool bSkip; - int reset_sof; - int tag_sof; - 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; +void check_challenges(bool file_given, uint8_t *data) { + int i, j, z, k; +// int frame_count = 0; + int response = 0; + uint8_t uid_byte[4]; + uint8_t rx[HITAG_FRAME_LEN]; + uint8_t unlocker[60][8]; + int u1 = 0; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + int t_wait = HITAG_T_WAIT_MAX; + int lastbit, reset_sof, STATE = 0;; + bool bStop; + int response_bit[200]; + unsigned char mask = 1; + unsigned char uid[32]; + unsigned char crc; - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); -// Reset the return status - bSuccessful = 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(); + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); - bQuiet = false; - bQuitTraceFull = true; + bQuiet = false; - LED_D_ON(); + 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; + // 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); - SpinDelay(50); - -// 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(); + // 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); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); -// Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); + // 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 + // TIMER_CLOCK1, used to capture edges of the tag frames + AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// 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; -// 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; -// 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 + // TC1: 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; - | 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; -// 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; + while (AT91C_BASE_TC0->TC_CV > 0) {}; -// Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; + // Reset the received frame, frame count and timing info + lastbit = 1; + bStop = false; + reset_sof = 1; + t_wait = 200; - reset_sof = 1; - t_wait = 200; + if (file_given) { + DbpString("Loading challenges..."); + memcpy((uint8_t *)unlocker, data, 60 * 8); + } - if (file_given) { - DbpString("Loading challenges..."); - memcpy((byte_t*)unlocker,data,60*8); - } + while (file_given && !bStop && !BUTTON_PRESS()) { + // Watchdog hit + WDT_HIT(); - while (file_given && !bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); + // Check if frame was captured and store it + if (rxlen > 0) { +// frame_count++; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, false); + } - // 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; - } - } - } - } + uint8_t *tx = txbuf; + size_t 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; + txlen = 5; + //start new authentication + memcpy(tx, "\xC0", nbytes(txlen)); + } else if (rxlen >= 67 && 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++; + } + } + k = 0; + for (i = 5; i < z; i += 2) { + uid[k] = response_bit[i]; + k++; + if (k > 31) + break; + } + 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; + } - 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; - txlen = 5; - //start new authentication - memcpy(tx, "\xc0", nbytes(txlen)); - } else if (rxlen >= 67 && 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++; - } - } - k = 0; - for (i = 5; i < z; i += 2) { - uid[k] = response_bit[i]; - k++; - if (k > 31) - break; - } - 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; - } + } else if (STATE == 1 && rxlen == 44) { + //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; - } else if (STATE == 1 && rxlen == 44) { - //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 >= ARRAYLEN(unlocker)) + bStop = !false; + for (i = 0; i < 8; i++) + tx[i] = unlocker[u1][i]; + u1++; - if (u1 >= (sizeof(unlocker) / sizeof(unlocker[0]))) - bStop = !false; - for (i = 0; i < 8; i++) - tx[i] = unlocker[u1][i]; - u1++; + } else if (STATE == 2 && rxlen >= 44) { + STATE = 0; + } - } else if (STATE == 2 && rxlen >= 44) { - 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; - // 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 - // 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))) {}; - 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); - // 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; - // 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++; + LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); + } - // 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; + bool bSkip = true; + int tag_sof = reset_sof; + response = 0; - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - response = 0; + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + // Check if falling edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); - // 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; - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + LED_B_ON(); - LED_B_ON(); + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { + if (rxlen > 0) + break; + } + } + } - // 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; - } - } - } - 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); + LEDsoff(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + StartTicks(); + + reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h new file mode 100644 index 000000000..49a885c4c --- /dev/null +++ b/armsrc/hitagS.h @@ -0,0 +1,31 @@ +//----------------------------------------------------------------------------- +// 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 +// +//----------------------------------------------------------------------------- + +#ifndef _HITAGS_H_ +#define _HITAGS_H_ + +#include +#include +#include +#include "hitag2_crypto.h" +#include "hitag.h" +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" +#include "BigBuf.h" + +void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data); +void ReadHitagS(hitag_function htf, hitag_data *htd); +void WritePageHitagS(hitag_function htf, hitag_data *htd, int page); +void check_challenges(bool file_given, uint8_t *data); + +#endif diff --git a/armsrc/iclass.c b/armsrc/iclass.c index a5481103b..1662a963a 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -12,16 +12,16 @@ //----------------------------------------------------------------------------- // 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!! //----------------------------------------------------------------------------- // // FIX: // ==== -// We still have sometimes a demodulation error when snooping iClass communication. +// We still have sometimes a demodulation error when sniffing iClass communication. // The resulting trace of a read-block-03 command may look something like this: // -// + 22279: : 0c 03 e8 01 +// + 22279: : 0c 03 e8 01 // // ...with an incorrect answer... // @@ -31,8 +31,8 @@ // // 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 +// + 21112: : 0c 03 e8 01 +// + 85: 0: TAG ff ff ff ff ff ff ff ff ea f5 // //----------------------------------------------------------------------------- @@ -60,11 +60,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); // The length of a received command will in most cases be no more than 18 bytes. // 32 should be enough! -#ifndef ICLASS_BUFFER_SIZE - #define ICLASS_BUFFER_SIZE 32 +#ifndef ICLASS_BUFFER_SIZE +#define ICLASS_BUFFER_SIZE 32 #endif -#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) +#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1) //----------------------------------------------------------------------------- // The software UART that receives commands from the reader, and its state @@ -75,7 +75,7 @@ typedef struct { enum { STATE_UNSYNCD, STATE_START_OF_COMMUNICATION, - STATE_RECEIVING + STATE_RECEIVING } state; uint16_t shiftReg; int bitCnt; @@ -97,33 +97,33 @@ typedef struct { typedef 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_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 syncBit; uint16_t shiftReg; - uint32_t buffer; - uint32_t buffer2; - uint32_t buffer3; - int buff; - int samples; + uint32_t buffer; + uint32_t buffer2; + uint32_t buffer3; + int buff; + int samples; int len; - enum { - SUB_NONE, - SUB_FIRST_HALF, - SUB_SECOND_HALF, - SUB_BOTH - } sub; + enum { + SUB_NONE, + SUB_FIRST_HALF, + SUB_SECOND_HALF, + SUB_BOTH + } sub; uint8_t *output; } tDemod; @@ -133,53 +133,53 @@ typedef struct { */ // Static vars for UART typedef struct { - bool synced; - bool frame; - bool frame_done; - uint8_t *buf; - int len; + bool synced; + bool frame; + bool frame_done; + uint8_t *buf; + int len; } tUart; static tUart Uart; -static void uart_reset(void){ - Uart.frame_done = false; - Uart.synced = false; - Uart.frame = false; +static void uart_reset(void) { + Uart.frame_done = false; + Uart.synced = false; + Uart.frame = false; } -static void uart_init(uint8_t *data){ - Uart.buf = data; - uart_reset(); +static void uart_init(uint8_t *data) { + Uart.buf = data; + uart_reset(); } static void uart_bit(uint8_t bit) { static uint8_t buf = 0xff; static uint8_t n_buf; - static uint8_t msg_byte; static int nmsg_byte; buf <<= 1; buf |= bit ? 1 : 0; if (!Uart.frame) { - if (buf == 0x7b) { // 0b0111 1011 + if (buf == 0x7b) { // 0b0111 1011 Uart.frame = true; n_buf = 0; Uart.len = 0; nmsg_byte = 0; } } else { + static uint8_t msg_byte; n_buf++; if (n_buf == 8) { msg_byte >>= 2; switch (buf) { case 0xbf: // 0 - 1011 1111 break; - case 0xef: // 1 - 1110 1111 - msg_byte |= (1<<6); + case 0xef: // 1 - 1110 1111 + msg_byte |= (1 << 6); break; case 0xfb: // 2 - 1111 1011 - msg_byte |= (2<<6); + msg_byte |= (2 << 6); break; case 0xfe: // 3 - 1111 1110 - msg_byte |= (3<<6); + msg_byte |= (3 << 6); break; case 0xdf: // eof - 1101 1111 Uart.frame = false; @@ -188,7 +188,7 @@ static void uart_bit(uint8_t bit) { break; default: Uart.frame = false; - Uart.synced = false; + Uart.synced = false; Dbprintf("[-] bad %02X at %d:%d", buf, Uart.len, nmsg_byte); } @@ -255,8 +255,8 @@ again: /* static void UartReset(){ - Uart.state = STATE_UNSYNCD; - Uart.shiftReg = 0; + Uart.state = STATE_UNSYNCD; + Uart.shiftReg = 0; Uart.bitCnt = 0; Uart.byteCnt = 0; Uart.posCnt = 0; @@ -279,220 +279,220 @@ static void UartReset(){ */ /* static RAMFUNC int OutOfNDecoding(int bit) { - //int error = 0; - int bitright; + //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.bitBuffer) { + Uart.bitBuffer = bit ^ 0xFF0; + return false; + } else { + Uart.bitBuffer <<= 4; + Uart.bitBuffer ^= bit; + } - if (Uart.state != STATE_UNSYNCD) { - Uart.posCnt++; + // 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.bitBuffer & Uart.syncBit) ^ Uart.syncBit) - bit = 0; - else - bit = 1; - - if (((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) - bitright = 0; - else - bitright = 1; - - if(bit != bitright) - bit = bitright; + if (Uart.state != STATE_UNSYNCD) { + Uart.posCnt++; - - // 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.bitBuffer & Uart.syncBit) ^ Uart.syncBit) + bit = 0; + else + bit = 1; - 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[0] = 0xf0; - Uart.byteCnt++; - } 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.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) + bitright = 0; + else + bitright = 1; - if (Uart.bitCnt == 8) { - Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff); - Uart.byteCnt++; - 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++; - Uart.bitCnt = 0; - Uart.shiftReg = 0; - Uart.nOutOfCnt = 0; - Uart.dropPosition = 0; - } - } + 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[0] = 0xf0; + Uart.byteCnt++; + } 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++; + 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++; + 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; - }*/ +/*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; + } + } 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; - // 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; } + if (!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; } + else if (bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; } - Uart.syncBit <<= 4; - Uart.state = STATE_START_OF_COMMUNICATION; - Uart.bitCnt = 0; - Uart.byteCnt = 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++; - } - } + 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.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; } */ @@ -501,25 +501,25 @@ static RAMFUNC int OutOfNDecoding(int bit) { //============================================================================= static tDemod Demod; static void DemodReset() { - Demod.bitCount = 0; - Demod.posCount = 0; - Demod.syncBit = 0; - Demod.shiftReg = 0; - Demod.buffer = 0; - Demod.buffer2 = 0; - Demod.buffer3 = 0; - Demod.buff = 0; - Demod.samples = 0; - Demod.len = 0; - Demod.sub = SUB_NONE; - Demod.state = DEMOD_UNSYNCD; + Demod.bitCount = 0; + Demod.posCount = 0; + Demod.syncBit = 0; + Demod.shiftReg = 0; + Demod.buffer = 0; + Demod.buffer2 = 0; + Demod.buffer3 = 0; + Demod.buff = 0; + Demod.samples = 0; + Demod.len = 0; + Demod.sub = SUB_NONE; + Demod.state = DEMOD_UNSYNCD; } static void DemodInit(uint8_t *data) { - Demod.output = data; - DemodReset(); + Demod.output = data; + DemodReset(); } -// UART debug +// UART debug // it adds the debug values which will be put in the tracelog, // visible on client when running 'hf list iclass' /* @@ -541,248 +541,255 @@ Recorded Activity (TraceLen = 162 bytes) 3232 | 3232 | Tag |bb! d4! bb! 02 02 08 04 bb! | ok | */ static void uart_debug(int error, int bit) { - 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++; + 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++; } /* * CARD TO READER -* in ISO15693-2 mode - Manchester +* in ISO15693-2 mode - Manchester * in ISO 14443b - BPSK coding * * Timings: -* ISO 15693-2 +* ISO 15693-2 * Tout = 330 µs, Tprog 1 = 4 to 15 ms, Tslot = 330 µs + (number of slots x 160 µs) * ISO 14443a -* Tout = 100 µs, Tprog = 4 to 15 ms, Tslot = 100 µs+ (number of slots x 80 µs) +* Tout = 100 µs, Tprog = 4 to 15 ms, Tslot = 100 µs+ (number of slots x 80 µs) * ISO 14443b - Tout = 76 µs, Tprog = 4 to 15 ms, Tslot = 119 µs+ (number of slots x 150 µs) + Tout = 76 µs, Tprog = 4 to 15 ms, Tslot = 119 µs+ (number of slots x 150 µs) * * * So for current implementation in ISO15693, its 330 µs from end of reader, to start of card. */ -static RAMFUNC int ManchesterDecoding_iclass( uint32_t v) { - int bit; - int modulation; - int error = 0; +static RAMFUNC int ManchesterDecoding_iclass(uint32_t v) { + int bit; + int modulation; + int error = 0; - bit = Demod.buffer; - Demod.buffer = Demod.buffer2; - Demod.buffer2 = Demod.buffer3; - Demod.buffer3 = v; + bit = Demod.buffer; + Demod.buffer = Demod.buffer2; + Demod.buffer2 = Demod.buffer3; + Demod.buffer3 = v; - // too few bits? - if (Demod.buff < 3) { - Demod.buff++; - return false; - } + // too few bits? + 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 (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 & 0x08) + Demod.syncBit = 0x08; - if (bit & 0x04) { - if (Demod.syncBit) - bit <<= 4; + if (bit & 0x04) { + if (Demod.syncBit) + bit <<= 4; - Demod.syncBit = 0x04; - } + Demod.syncBit = 0x04; + } - if (bit & 0x02) { - if (Demod.syncBit) - bit <<= 2; + if (bit & 0x02) { + if (Demod.syncBit) + bit <<= 2; - Demod.syncBit = 0x02; - } + Demod.syncBit = 0x02; + } - if (bit & 0x01 && Demod.syncBit) - Demod.syncBit = 0x01; + 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.samples = 0; + if (Demod.syncBit) { + Demod.len = 0; + Demod.state = DEMOD_START_OF_COMMUNICATION; + Demod.sub = SUB_FIRST_HALF; + Demod.bitCount = 0; + Demod.shiftReg = 0; + Demod.samples = 0; - if (Demod.posCount) { + if (Demod.posCount) { - 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; + 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; - uart_debug(error, bit); - return false; - } - } - error = 0; - } - return false; - } + } else { + // SOF must be long burst... otherwise stay unsynced!!! + if (!(Demod.buffer2 & Demod.syncBit) || !(Demod.buffer3 & Demod.syncBit)) { + Demod.state = DEMOD_UNSYNCD; + error = 0x88; + uart_debug(error, bit); + return false; + } + } + } + return false; + } - // state is DEMOD is in SYNC from here on. - - modulation = bit & Demod.syncBit; - modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; - Demod.samples += 4; + // state is DEMOD is in SYNC from here on. - if (Demod.posCount == 0) { - Demod.posCount = 1; - Demod.sub = (modulation) ? SUB_FIRST_HALF : SUB_NONE; - return false; - } + modulation = bit & Demod.syncBit; + modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; + Demod.samples += 4; - Demod.posCount = 0; + if (Demod.posCount == 0) { + Demod.posCount = 1; + Demod.sub = (modulation) ? SUB_FIRST_HALF : SUB_NONE; + return false; + } - if (modulation) { - - if (Demod.sub == SUB_FIRST_HALF) - Demod.sub = SUB_BOTH; - else - Demod.sub = SUB_SECOND_HALF; - } - - if (Demod.sub == SUB_NONE) { - if (Demod.state == DEMOD_SOF_COMPLETE) { - Demod.output[Demod.len] = 0x0f; - Demod.len++; - Demod.state = DEMOD_UNSYNCD; - return true; - } else { - Demod.state = DEMOD_ERROR_WAIT; - error = 0x33; - } - } + Demod.posCount = 0; - switch (Demod.state) { - - case DEMOD_START_OF_COMMUNICATION: - if (Demod.sub == SUB_BOTH) { + if (modulation) { - 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_SOF_COMPLETE; - } 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; + if (Demod.sub == SUB_FIRST_HALF) + Demod.sub = SUB_BOTH; + else + Demod.sub = SUB_SECOND_HALF; + } - 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); // right align data - Demod.output[Demod.len] = Demod.shiftReg & 0xff; - Demod.len++; - } + if (Demod.sub == SUB_NONE) { + if (Demod.state == DEMOD_SOF_COMPLETE) { + Demod.output[Demod.len] = 0x0f; + Demod.len++; + Demod.state = DEMOD_UNSYNCD; + return true; + } else { + Demod.state = DEMOD_ERROR_WAIT; + error = 0x33; + } + } - Demod.state = DEMOD_UNSYNCD; - return true; - } else { - Demod.output[Demod.len] = 0xad; - Demod.state = DEMOD_ERROR_WAIT; - error = 0x03; - } - break; + switch (Demod.state) { - case DEMOD_ERROR_WAIT: - Demod.state = DEMOD_UNSYNCD; - break; + case DEMOD_START_OF_COMMUNICATION: + if (Demod.sub == SUB_BOTH) { - default: - Demod.output[Demod.len] = 0xdd; - Demod.state = DEMOD_UNSYNCD; - break; - } + 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; - if (Demod.bitCount >= 8) { - Demod.shiftReg >>= 1; - Demod.output[Demod.len] = (Demod.shiftReg & 0xff); - Demod.len++; - Demod.bitCount = 0; - Demod.shiftReg = 0; - } + 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_SOF_COMPLETE; + } 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); // right align data + Demod.output[Demod.len] = Demod.shiftReg & 0xff; + Demod.len++; + } + + 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 >= 8) { + Demod.shiftReg >>= 1; + Demod.output[Demod.len] = (Demod.shiftReg & 0xff); + Demod.len++; + Demod.bitCount = 0; + Demod.shiftReg = 0; + } + + if (error) { + uart_debug(error, bit); + return true; + } - if (error) { - uart_debug(error, bit); - return true; - } - return false; } @@ -790,50 +797,51 @@ static RAMFUNC int ManchesterDecoding_iclass( uint32_t v) { // Finally, a `sniffer' for iClass communication // Both sides of communication! //============================================================================= -static void iclass_setup_sniff(void){ - if (MF_DBGLEVEL > 3) Dbprintf("iclass_setup_sniff Enter"); +static void iclass_setup_sniff(void) { + if (DBGLEVEL > 3) Dbprintf("iclass_setup_sniff Enter"); - LEDsoff(); + LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Set up the synchronous serial port - FpgaSetupSsc(); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); + // Set up the synchronous serial port + FpgaSetupSsc(); - // Initialize Demod and Uart structs - DemodInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); - uart_init(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - //UartInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); + // Initialize Demod and Uart structs + DemodInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - if (MF_DBGLEVEL > 1) { - // Print debug information about the buffer sizes - Dbprintf("[+] Sniffing buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", ICLASS_BUFFER_SIZE); - Dbprintf(" tag -> Reader: %i bytes", ICLASS_BUFFER_SIZE); - Dbprintf(" DMA: %i bytes", ICLASS_DMA_BUFFER_SIZE); - } + uart_init(BigBuf_malloc(ICLASS_BUFFER_SIZE)); + //UartInit(BigBuf_malloc(ICLASS_BUFFER_SIZE)); - // Set FPGA in the appropriate mode + if (DBGLEVEL > 1) { + // Print debug information about the buffer sizes + Dbprintf("[+] Sniffing buffers initialized:"); + Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); + Dbprintf(" Reader -> tag: %i bytes", ICLASS_BUFFER_SIZE); + Dbprintf(" tag -> Reader: %i bytes", ICLASS_BUFFER_SIZE); + Dbprintf(" DMA: %i bytes", ICLASS_DMA_BUFFER_SIZE); + } + + // Set FPGA in the appropriate mode // put the FPGA in the appropriate mode FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); - SpinDelay(200); - - // Start the SSP timer - StartCountSspClk(); - - LED_A_ON(); - if (MF_DBGLEVEL > 3) Dbprintf("[+] iclass_setup_sniff Exit"); + SpinDelay(200); + + // Start the SSP timer + StartCountSspClk(); + + LED_A_ON(); + if (DBGLEVEL > 3) Dbprintf("[+] iclass_setup_sniff Exit"); } //----------------------------------------------------------------------------- @@ -844,130 +852,130 @@ static void iclass_setup_sniff(void){ // turn off afterwards void RAMFUNC SniffIClass(void) { - //int datalen = 0; - uint32_t previous_data = 0; - uint32_t time_0 = 0, time_start = 0, time_stop = 0; + //int datalen = 0; + uint32_t previous_data = 0; + uint32_t time_0 = 0, time_start = 0, time_stop; uint32_t sniffCounter = 0; - bool TagIsActive = false; - bool ReaderIsActive = false; - - iclass_setup_sniff(); - + bool TagIsActive = false; + bool ReaderIsActive = false; + + iclass_setup_sniff(); + // The DMA buffer, used to stream samples from the FPGA - // *dmaBuf is the start reference. + // *dmaBuf is the start reference. uint8_t *dmaBuf = BigBuf_malloc(ICLASS_DMA_BUFFER_SIZE); - // pointer to samples from fpga + // pointer to samples from fpga uint8_t *data = dmaBuf; - // Setup and start DMA. - if ( !FpgaSetupSscDma(dmaBuf, ICLASS_DMA_BUFFER_SIZE) ){ - if (MF_DBGLEVEL > 1) DbpString("[-] FpgaSetupSscDma failed. Exiting"); - return; - } + // Setup and start DMA. + if (!FpgaSetupSscDma(dmaBuf, ICLASS_DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) DbpString("[-] FpgaSetupSscDma failed. Exiting"); + return; + } - // time ZERO, the point from which it all is calculated. - time_0 = GetCountSspClk(); + // time ZERO, the point from which it all is calculated. + time_0 = GetCountSspClk(); - int div = 0; - uint8_t tag_byte = 0, foo = 0; + int divi = 0; + uint8_t tag_byte = 0, foo = 0; // loop and listen - // every sample (1byte in data), - // contains HIGH nibble = reader data - // contains LOW nibble = tag data - // so two bytes are needed in order to get 1byte of either reader or tag data. (ie 2 sample bytes) - // since reader data is manchester encoded, we need 2bytes of data in order to get one demoded byte. (ie: 4 sample bytes) - while (!BUTTON_PRESS()) { + // every sample (1byte in data), + // contains HIGH nibble = reader data + // contains LOW nibble = tag data + // so two bytes are needed in order to get 1byte of either reader or tag data. (ie 2 sample bytes) + // since reader data is manchester encoded, we need 2bytes of data in order to get one demoded byte. (ie: 4 sample bytes) + while (!BUTTON_PRESS()) { WDT_HIT(); - previous_data <<= 8; - previous_data |= *data; - - sniffCounter++; - data++; + previous_data <<= 8; + previous_data |= *data; - if (data == dmaBuf + ICLASS_DMA_BUFFER_SIZE) { - data = dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = ICLASS_DMA_BUFFER_SIZE; - } - - if ( *data & 0xF) { - //tag_byte <<= 1; - tag_byte ^= (1 << 4); - foo ^= (1 << (3 - div)); - Dbprintf(" %d|%x == %d|%x", tag_byte, tag_byte, foo, foo); - } - div++; - - // every odd sample - if (sniffCounter & 0x01) { - // no need to try decoding reader data if the tag is sending - // READER TO CARD - if (!TagIsActive) { - LED_C_INV(); - // HIGH nibble is always reader data. - uint8_t reader_byte = (previous_data & 0xF0) | (*data >> 4); - uart_samples(reader_byte); - if (Uart.frame_done) { - time_stop = GetCountSspClk() - time_0; - LogTrace( Uart.buf, Uart.len, time_start, time_stop, NULL, true); - DemodReset(); - uart_reset(); - } else { - time_start = GetCountSspClk() - time_0; - } - ReaderIsActive = Uart.frame_done; - } - } - // every four sample - if ( (sniffCounter % 4) == 0) { - // need two samples to feed Manchester - // no need to try decoding tag data if the reader is sending - and we cannot afford the time - // CARD TO READER - if (!ReaderIsActive) { - LED_C_INV(); - // LOW nibble is always tag data. - /* - - - uint32_t tag_byte = - ((previous_data & 0x0F000000) >> 8 ) | - ((previous_data & 0x000F0000) >> 4 ) | - ((previous_data & 0x00000F00) ) | - ((previous_data & 0x0000000F) << 4 ) | - (*data & 0xF); - */ - - - //uint8_t tag_byte = ((previous_data & 0xF) << 4 ) | (*data & 0xF); - if (ManchesterDecoding_iclass(foo)) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); - DemodReset(); - uart_reset(); - } else { - time_start = GetCountSspClk() - time_0; - } - TagIsActive = (Demod.state != DEMOD_UNSYNCD); - } - tag_byte = 0; - foo = 0; - div = 0; - } - } // end main loop + sniffCounter++; + data++; - if (MF_DBGLEVEL >= 1) { - DbpString("[+] Sniff statistics:"); - Dbhexdump(ICLASS_DMA_BUFFER_SIZE, data, false); - } - - switch_off(); + if (data == dmaBuf + ICLASS_DMA_BUFFER_SIZE) { + data = dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = ICLASS_DMA_BUFFER_SIZE; + } + + if (*data & 0xF) { + //tag_byte <<= 1; + tag_byte ^= (1 << 4); + foo ^= (1 << (3 - divi)); + Dbprintf(" %d|%x == %d|%x", tag_byte, tag_byte, foo, foo); + } + divi++; + + // every odd sample + if (sniffCounter & 0x01) { + // no need to try decoding reader data if the tag is sending + // READER TO CARD + if (!TagIsActive) { + LED_C_INV(); + // HIGH nibble is always reader data. + uint8_t reader_byte = (previous_data & 0xF0) | (*data >> 4); + uart_samples(reader_byte); + if (Uart.frame_done) { + time_stop = GetCountSspClk() - time_0; + LogTrace(Uart.buf, Uart.len, time_start, time_stop, NULL, true); + DemodReset(); + uart_reset(); + } else { + time_start = GetCountSspClk() - time_0; + } + ReaderIsActive = Uart.frame_done; + } + } + // every four sample + if ((sniffCounter % 4) == 0) { + // need two samples to feed Manchester + // no need to try decoding tag data if the reader is sending - and we cannot afford the time + // CARD TO READER + if (!ReaderIsActive) { + LED_C_INV(); + // LOW nibble is always tag data. + /* + + + uint32_t tag_byte = + ((previous_data & 0x0F000000) >> 8 ) | + ((previous_data & 0x000F0000) >> 4 ) | + ((previous_data & 0x00000F00) ) | + ((previous_data & 0x0000000F) << 4 ) | + (*data & 0xF); + */ + + + //uint8_t tag_byte = ((previous_data & 0xF) << 4 ) | (*data & 0xF); + if (ManchesterDecoding_iclass(foo)) { + time_stop = GetCountSspClk() - time_0; + LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); + DemodReset(); + uart_reset(); + } else { + time_start = GetCountSspClk() - time_0; + } + TagIsActive = (Demod.state != DEMOD_UNSYNCD); + } + tag_byte = 0; + foo = 0; + divi = 0; + } + } // end main loop + + if (DBGLEVEL >= 1) { + DbpString("[+] Sniff statistics:"); + Dbhexdump(ICLASS_DMA_BUFFER_SIZE, data, false); + } + + switch_off(); } -void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { - int i; - for(i = 0; i < 8; i++) - rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i+1)%8] << 5); +void rotateCSN(uint8_t *originalCSN, uint8_t *rotatedCSN) { + int i; + for (i = 0; i < 8; i++) + rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i + 1) % 8] << 5); } //----------------------------------------------------------------------------- @@ -976,147 +984,164 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { // Stop when button is pressed // Or return TRUE when command is captured //----------------------------------------------------------------------------- -static bool GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { +static bool 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(); - uart_init(received); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uart_init(received); - while (!BUTTON_PRESS()) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // clear RXRDY: + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + + while (!BUTTON_PRESS()) { WDT_HIT(); - // keep tx buffer in a defined state anyway. + // keep tx buffer in a defined state anyway. if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) AT91C_BASE_SSC->SSC_THR = 0x00; - // wait for byte to become available in rx holding register + // wait for byte to become available in rx holding register if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; uart_samples(b); if (Uart.frame_done) { *len = Uart.len; - return true; - } + return true; + } } } - return false; + return false; } static uint8_t encode4Bits(const uint8_t b) { - // OTA, the least significant bits first - // Manchester encoding added - // The columns are - // 1 - Bit value to send - // 2 - Reversed (big-endian) - // 3 - Machester Encoded - // 4 - Hex values + // OTA, the least significant bits first + // Manchester encoding added + // The columns are + // 1 - Bit value to send + // 2 - Reversed (big-endian) + // 3 - Machester Encoded + // 4 - Hex values - uint8_t c = b & 0xF; - 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 - } + uint8_t c = b & 0xF; + 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 + } } //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- static void CodeIClassTagAnswer(const uint8_t *cmd, int 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) - * - * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, - * works like this. - * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). - * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us - * - * In this mode - * SOF can be written as 00011101 = 0x1D - * EOF can be written as 10111000 = 0xb8 - * logic 1 be written as 01 = 0x1 - * logic 0 be written as 10 = 0x2 - * - * */ - ToSendReset(); + /* + * 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) + * + * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, + * works like this. + * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). + * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us + * + * In this mode + * SOF can be written as 00011101 = 0x1D + * EOF can be written as 10111000 = 0xb8 + * logic 1 be written as 01 = 0x1 + * logic 0 be written as 10 = 0x2 + * + * */ + ToSendReset(); - // Send SOF - ToSend[++ToSendMax] = 0x1D; - - int i; - for(i = 0; i < len; i++) { - uint8_t b = cmd[i]; - ToSend[++ToSendMax] = encode4Bits(b & 0xF); // least significant half - ToSend[++ToSendMax] = encode4Bits((b >> 4) & 0xF); // most significant half - } + // Send SOF + ToSend[++ToSendMax] = 0x1D; - // Send EOF - ToSend[++ToSendMax] = 0xB8; - //lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end - // Convert from last byte pos to length - ToSendMax++; + int i; + for (i = 0; i < len; i++) { + uint8_t b = cmd[i]; + ToSend[++ToSendMax] = encode4Bits(b & 0xF); // least significant half + ToSend[++ToSendMax] = encode4Bits((b >> 4) & 0xF); // most significant half + } + + // Send EOF + ToSend[++ToSendMax] = 0xB8; + //lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end + // Convert from last byte pos to length + ToSendMax++; } -// Only SOF +// Only SOF static void CodeIClassTagSOF() { - //So far a dummy implementation, not used - //int lastProxToAirDuration =0; + //So far a dummy implementation, not used + //int lastProxToAirDuration =0; - ToSendReset(); - // Send SOF - ToSend[++ToSendMax] = 0x1D; - // lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning + ToSendReset(); + // Send SOF + ToSend[++ToSendMax] = 0x1D; + // lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning - // Convert from last byte pos to length - ToSendMax++; + // Convert from last byte pos to length + ToSendMax++; } /** * @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) + * - 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 @@ -1124,107 +1149,107 @@ static void CodeIClassTagSOF() { // turn off afterwards void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - if (MF_DBGLEVEL > 3) Dbprintf("[+] iClass_simulate Enter"); + if (DBGLEVEL > 3) Dbprintf("[+] iClass_simulate Enter"); - LEDsoff(); + LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // this will clear out bigbuf memory, the eload command must select this before! - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaSetupSsc(); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Enable and clear the trace - clear_trace(); - set_tracing(true); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // this will clear out bigbuf memory, the eload command must select this before! + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaSetupSsc(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - uint32_t simType = arg0; - uint32_t numberOfCSNS = arg1; + // Enable and clear the trace + clear_trace(); + set_tracing(true); - //Use the emulator memory for SIM - uint8_t *emulator = BigBuf_get_EM_addr(); - uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; - - if (simType == 0) { - // Use the CSN from commandline - memcpy(emulator, datain, 8); - doIClassSimulation(MODE_SIM_CSN, NULL); - } else if (simType == 1) { - //Default CSN - uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; - // Use the CSN from commandline - memcpy(emulator, csn_crc, 8); - doIClassSimulation(MODE_SIM_CSN, NULL); - } else if (simType == 2) { + uint32_t simType = arg0; + uint32_t numberOfCSNS = arg1; - 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 offlne-attack - // in order to obtain the keys, as in the "dismantling iclass"-paper. - #define EPURSE_MAC_SIZE 16 - int i = 0; - for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < USB_CMD_DATA_SIZE; i++) { - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. + //Use the emulator memory for SIM + uint8_t *emulator = BigBuf_get_EM_addr(); + uint8_t mac_responses[PM3_CMD_DATA_SIZE] = { 0 }; - memcpy(emulator, datain + (i*8), 8); - - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses+i * EPURSE_MAC_SIZE)) { - // Button pressed - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE); - goto out; - } - } - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE); + if (simType == 0) { + // Use the CSN from commandline + memcpy(emulator, datain, 8); + doIClassSimulation(MODE_SIM_CSN, NULL); + } else if (simType == 1) { + //Default CSN + uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; + // Use the CSN from commandline + memcpy(emulator, csn_crc, 8); + doIClassSimulation(MODE_SIM_CSN, NULL); + } else if (simType == 2) { - } else if (simType == 3){ - //This is 'full sim' mode, where we use the emulator storage for data. - //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command - doIClassSimulation(MODE_FULLSIM, NULL); - } else if (simType == 4){ + 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 offlne-attack + // in order to obtain the keys, as in the "dismantling iclass"-paper. +#define EPURSE_MAC_SIZE 16 + int i = 0; + for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { + // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. - // This is the KEYROLL version of sim 2. - // the collected data (mac_response) is doubled out since we are trying to collect both keys in the keyroll process. - // Keyroll iceman 9 csns * 8 * 2 = 144 - // keyroll CARL55 15csns * 8 * 2 = 15 * 8 * 2 = 240 - Dbprintf("[+] going into attack keyroll 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 offlne-attack - // in order to obtain the keys, as in the "dismantling iclass"-paper. - - // keyroll mode, reader swaps between old key and new key alternatively when fail a authentication. - // attack below is same as SIM 2, but we run the CSN twice to collected the mac for both keys. - int i = 0; - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. iceman fork uses 9 CSNS - for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < USB_CMD_DATA_SIZE; i++) { + memcpy(emulator, datain + (i * 8), 8); - memcpy(emulator, datain + (i*8), 8); - - // keyroll 1 - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE )) { - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); - // Button pressed - goto out; - } + if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + // Button pressed + reply_old(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE); + goto out; + } + } + reply_old(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE); - // keyroll 2 - if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE )) { - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE* 2); - // Button pressed - goto out; - } - } - // double the amount of collected data. - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2 ); - - } 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. - DbpString("[-] the mode is not implemented, reserved for future use"); - } + } else if (simType == 3) { + //This is 'full sim' mode, where we use the emulator storage for data. + //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command + doIClassSimulation(MODE_FULLSIM, NULL); + } else if (simType == 4) { -out: - switch_off(); - BigBuf_free_keep_EM(); + // This is the KEYROLL version of sim 2. + // the collected data (mac_response) is doubled out since we are trying to collect both keys in the keyroll process. + // Keyroll iceman 9 csns * 8 * 2 = 144 + // keyroll CARL55 15csns * 8 * 2 = 15 * 8 * 2 = 240 + Dbprintf("[+] going into attack keyroll 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 offlne-attack + // in order to obtain the keys, as in the "dismantling iclass"-paper. + + // keyroll mode, reader swaps between old key and new key alternatively when fail a authentication. + // attack below is same as SIM 2, but we run the CSN twice to collected the mac for both keys. + int i = 0; + // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. iceman fork uses 9 CSNS + for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < PM3_CMD_DATA_SIZE; i++) { + + memcpy(emulator, datain + (i * 8), 8); + + // keyroll 1 + if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE)) { + reply_old(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + // Button pressed + goto out; + } + + // keyroll 2 + if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE)) { + reply_old(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + // Button pressed + goto out; + } + } + // double the amount of collected data. + reply_old(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i * 2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2); + + } 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. + DbpString("[-] the mode is not implemented, reserved for future use"); + } + +out: + switch_off(); + BigBuf_free_keep_EM(); } /** @@ -1232,384 +1257,404 @@ out: * @param csn - csn to use * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ -int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) { +int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { - // free eventually allocated BigBuf memory - BigBuf_free_keep_EM(); - - State cipher_state; + // free eventually allocated BigBuf memory + BigBuf_free_keep_EM(); - uint8_t *csn = BigBuf_get_EM_addr(); - uint8_t *emulator = csn; - uint8_t sof_data[] = { 0x0F} ; - - // CSN followed by two CRC bytes - uint8_t anticoll_data[10] = { 0 }; - uint8_t csn_data[10] = { 0 }; - memcpy(csn_data, csn, sizeof(csn_data)); + State cipher_state; - // Construct anticollision-CSN - rotateCSN(csn_data, anticoll_data); + uint8_t *csn = BigBuf_get_EM_addr(); + uint8_t *emulator = csn; + uint8_t sof_data[] = { 0x0F} ; - // Compute CRC on both CSNs - AddCrc(anticoll_data, 8); - AddCrc(csn_data, 8); - - uint8_t diversified_key[8] = { 0 }; - // e-Purse - uint8_t card_challenge_data[8] = { 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; - //uint8_t card_challenge_data[8] = { 0 }; - if (simulationMode == MODE_FULLSIM) { - //The diversified key should be stored on block 3 - //Get the diversified key from emulator memory - memcpy(diversified_key, emulator+(8*3),8); + // CSN followed by two CRC bytes + uint8_t anticoll_data[10] = { 0 }; + uint8_t csn_data[10] = { 0 }; + memcpy(csn_data, csn, sizeof(csn_data)); - //Card challenge, a.k.a e-purse is on block 2 - memcpy(card_challenge_data, emulator + (8 * 2) ,8); - //Precalculate the cipher state, feeding it the CC - cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); - } - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - - int exitLoop = 0; - // Reader 0a - // Tag 0f - // Reader 0c - // Tag anticoll. CSN - // Reader 81 anticoll. CSN - // Tag CSN + // Construct anticollision-CSN + rotateCSN(csn_data, anticoll_data); - uint8_t *modulated_response; - int modulated_response_size = 0; - uint8_t* trace_data = NULL; - int trace_data_size = 0; + // Compute CRC on both CSNs + AddCrc(anticoll_data, 8); + AddCrc(csn_data, 8); - // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(2); - int resp_sof_Len; + uint8_t diversified_key[8] = { 0 }; + // e-Purse + uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + //uint8_t card_challenge_data[8] = { 0 }; + if (simulationMode == MODE_FULLSIM) { + //The diversified key should be stored on block 3 + //Get the diversified key from emulator memory + memcpy(diversified_key, emulator + (8 * 3), 8); - // 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(28); - int resp_anticoll_len; + //Card challenge, a.k.a e-purse is on block 2 + memcpy(card_challenge_data, emulator + (8 * 2), 8); + //Precalculate the cipher state, feeding it the CC + cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); + } + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } - // CSN - // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(28); - int resp_csn_len; + int exitLoop = 0; + // Reader 0a + // Tag 0f + // Reader 0c + // Tag anticoll. CSN + // Reader 81 anticoll. CSN + // Tag CSN - // configuration picopass 2ks - uint8_t *resp_conf = BigBuf_malloc(28); - int resp_conf_len; - uint8_t conf_data[10] = {0x12,0xFF,0xFF,0xFF,0x7F,0x1F,0xFF,0x3C,0x00,0x00}; - AddCrc(conf_data, 8); - - // e-Purse - // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_malloc(28); - int resp_cc_len; + uint8_t *modulated_response; + int modulated_response_size = 0; + uint8_t *trace_data = NULL; + int trace_data_size = 0; - // Application Issuer Area - uint8_t *resp_aia = BigBuf_malloc(28); - int resp_aia_len; - uint8_t aia_data[10] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00}; - AddCrc(aia_data, 8); + // Respond SOF -- takes 1 bytes + uint8_t *resp_sof = BigBuf_malloc(2); + int resp_sof_Len; - // receive command - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - int len = 0; + // 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(28); + int resp_anticoll_len; - // Prepare card messages - ToSendMax = 0; + // CSN + // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) + uint8_t *resp_csn = BigBuf_malloc(28); + int resp_csn_len; - // First card answer: SOF - CodeIClassTagSOF(); - memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax; - - // Anticollision CSN - CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data)); - memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax; - - // CSN - CodeIClassTagAnswer(csn_data, sizeof(csn_data)); - memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax; + // configuration picopass 2ks + uint8_t *resp_conf = BigBuf_malloc(28); + int resp_conf_len; + uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; + AddCrc(conf_data, 8); - // Configuration - CodeIClassTagAnswer(conf_data, sizeof(conf_data)); - memcpy(resp_conf, ToSend, ToSendMax); resp_conf_len = ToSendMax; - - // e-Purse - CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; + // e-Purse + // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) + uint8_t *resp_cc = BigBuf_malloc(28); + int resp_cc_len; - // Application Issuer Area - CodeIClassTagAnswer(aia_data, sizeof(aia_data)); - memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax; + // Application Issuer Area + uint8_t *resp_aia = BigBuf_malloc(28); + int resp_aia_len; + uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AddCrc(aia_data, 8); - //This is used for responding to READ-block commands or other data which is dynamically generated - //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(8 + 2);//8 bytes data + 2byte CRC is max tag answer + // receive command + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + int len = 0; - //Then storage for the modulated data - //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc( (8+2) * 2 + 2); + // Prepare card messages + ToSendMax = 0; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - SpinDelay(100); - StartCountSspClk(); + // First card answer: SOF + CodeIClassTagSOF(); + memcpy(resp_sof, ToSend, ToSendMax); + resp_sof_Len = ToSendMax; - // To control where we are in the protocol - uint32_t time_0 = GetCountSspClk(); - uint32_t t2r_stime = 0, t2r_etime = 0; - uint32_t r2t_stime = 0, r2t_etime = 0; + // Anticollision CSN + CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data)); + memcpy(resp_anticoll, ToSend, ToSendMax); + resp_anticoll_len = ToSendMax; - LED_A_ON(); - bool buttonPressed = false; + // CSN + CodeIClassTagAnswer(csn_data, sizeof(csn_data)); + memcpy(resp_csn, ToSend, ToSendMax); + resp_csn_len = ToSendMax; - while (!exitLoop) { - WDT_HIT(); + // Configuration + CodeIClassTagAnswer(conf_data, sizeof(conf_data)); + memcpy(resp_conf, ToSend, ToSendMax); + resp_conf_len = ToSendMax; - //Signal tracer, can be used to get a trigger for an oscilloscope.. - LED_B_OFF(); LED_C_OFF(); - - r2t_stime = (GetCountSspClk() - time_0) << 4; - if (!GetIClassCommandFromReader(receivedCmd, &len, 0)) { - buttonPressed = true; - exitLoop = true; - continue; - } - r2t_etime = ((GetCountSspClk() - time_0) << 4 ) - r2t_stime; - - // 330us normal wait, adjusted for our execution + // e-Purse + CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); + memcpy(resp_cc, ToSend, ToSendMax); + resp_cc_len = ToSendMax; - LED_C_ON(); //Signal tracer + // Application Issuer Area + CodeIClassTagAnswer(aia_data, sizeof(aia_data)); + memcpy(resp_aia, ToSend, ToSendMax); + resp_aia_len = ToSendMax; - if (receivedCmd[0] == ICLASS_CMD_ACTALL ) { // 0x0A - // Reader in anticollission phase - modulated_response = resp_sof; modulated_response_size = resp_sof_Len; //order = 1; - trace_data = sof_data; - trace_data_size = sizeof(sof_data); - // adjusted for 330 + (160*num of slot) - goto send; - } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY) { // 0x0C - if (len == 1) { - // Reader asks for anticollission CSN - modulated_response = resp_anticoll; modulated_response_size = resp_anticoll_len; //order = 2; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); - goto send; - } - if (len == 4){ - // block0,1,2,5 is always readable. - switch (receivedCmd[1]){ - case 0: // csn (0c 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 (0c 01) - modulated_response = resp_conf; modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); - break; - case 2: // e-purse (0c 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 5:// Application Issuer Area (0c 05) - modulated_response = resp_aia; modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - break; - default: break; - } - goto send; - } - - } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { // 0x81 - // Reader selects anticollission CSN. - // Tag sends the corresponding real CSN - modulated_response = resp_csn; modulated_response_size = resp_csn_len; //order = 3; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - goto send; - } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD) { // 0x88 - // Read e-purse (88 02) - modulated_response = resp_cc; modulated_response_size = resp_cc_len; //order = 4; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); - goto send; - } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KC) { // 0x18 - // Read e-purse (18 02) - modulated_response = resp_cc; modulated_response_size = resp_cc_len; //order = 4; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); - goto send; - } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { // 0x05 - // Reader random and reader MAC!!! - if (simulationMode == MODE_FULLSIM) { - // NR, from reader, is in receivedCmd +1 - opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); + //This is used for responding to READ-block commands or other data which is dynamically generated + //First the 'trace'-data, not encoded for FPGA + uint8_t *data_generic_trace = BigBuf_malloc(8 + 2);//8 bytes data + 2byte CRC is max tag answer - trace_data = data_generic_trace; - trace_data_size = 4; - CodeIClassTagAnswer(trace_data , trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } else { - // Not fullsim, we don't respond - // We do not know what to answer, so lets keep quiet - modulated_response = resp_sof; modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; - - if (simulationMode == MODE_EXIT_AFTER_MAC) { - - if ( MF_DBGLEVEL == MF_DBG_EXTENDED) { - Dbprintf("[+] 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]); - Dbprintf("[+] RDR: (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 { - Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]); - } - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf + 8, receivedCmd+1, 8); - } - exitLoop = true; - } - } - goto send; - } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { - // Reader ends the session - modulated_response = resp_sof; modulated_response_size = 0; //order = 0; - trace_data = NULL; - trace_data_size = 0; - goto send; - } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){ // 0x0C - //Read block - uint16_t blk = receivedCmd[1]; - //Take the data... - memcpy(data_generic_trace, emulator+(blk << 3),8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIClassTagAnswer(trace_data , trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - goto send; - } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_UPDATE) { - - //Probably the reader wants to update the nonce. Let's just ignore that for now. - // OBS! If this is implemented, don't forget to regenerate the cipher_state - //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| + //Then storage for the modulated data + //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) + uint8_t *data_response = BigBuf_malloc((8 + 2) * 2 + 2); - //Take the data... - memcpy(data_generic_trace, receivedCmd+2, 8); - AddCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); - - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; -// response_delay = 4600 * 1.5; // tPROG 4-15ms - goto send; -// } else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) { // 0x84 - //Pagesel - //Pagesel enables to select a page in the selected chip memory and return its configuration block - //Chips with a single page will not answer to this command - // It appears we're fine ignoring this. - //Otherwise, we should answer 8bytes (block) + 2bytes CRC -// } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F - } else { - //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 - // Never seen this command before - if ( MF_DBGLEVEL == MF_DBG_EXTENDED) - print_result("[-] Unhandled command received ", receivedCmd, len); - - // Do not respond - modulated_response = resp_sof; - modulated_response_size = 0; //order = 0; - trace_data = NULL; - trace_data_size = 0; - } + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + SpinDelay(100); + StartCountSspClk(); -send: - /** - A legit tag has about 330us delay between reader EOT and tag SOF. - **/ - if (modulated_response_size > 0) { - t2r_stime = (GetCountSspClk() - time_0) << 4; - SendIClassAnswer(modulated_response, modulated_response_size, 0); - t2r_etime = ((GetCountSspClk() - time_0) << 4 ) - t2r_stime; - } + // To control where we are in the protocol + uint32_t time_0 = GetCountSspClk(); + uint32_t t2r_stime = 0, t2r_etime = 0; + uint32_t r2t_stime, r2t_etime = 0; - LogTrace(receivedCmd, len, r2t_stime, r2t_etime, NULL, true); - - if (trace_data != NULL) - LogTrace(trace_data, trace_data_size, t2r_stime, t2r_etime, NULL, false); - } + LED_A_ON(); + bool buttonPressed = false; - LEDsoff(); - - if (buttonPressed) - DbpString("[+] button pressed"); - - return buttonPressed; + while (!exitLoop) { + WDT_HIT(); + + //Signal tracer, can be used to get a trigger for an oscilloscope.. + LED_B_OFF(); + LED_C_OFF(); + + r2t_stime = (GetCountSspClk() - time_0) << 4; + if (!GetIClassCommandFromReader(receivedCmd, &len, 0)) { + buttonPressed = true; + exitLoop = true; + continue; + } + r2t_etime = ((GetCountSspClk() - time_0) << 4) - r2t_stime; + + // 330us normal wait, adjusted for our execution + + LED_C_ON(); //Signal tracer + + if (receivedCmd[0] == ICLASS_CMD_ACTALL) { // 0x0A + // Reader in anticollission phase + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; //order = 1; + trace_data = sof_data; + trace_data_size = sizeof(sof_data); + // adjusted for 330 + (160*num of slot) + goto send; + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY) { // 0x0C + if (len == 1) { + // Reader asks for anticollission CSN + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; //order = 2; + trace_data = anticoll_data; + trace_data_size = sizeof(anticoll_data); + goto send; + } + if (len == 4) { + // block0,1,2,5 is always readable. + switch (receivedCmd[1]) { + case 0: // csn (0c 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 (0c 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_data; + trace_data_size = sizeof(conf_data); + break; + case 2: // e-purse (0c 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 5:// Application Issuer Area (0c 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + break; + default: + break; + } + goto send; + } + + } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { // 0x81 + // Reader selects anticollission CSN. + // Tag sends the corresponding real CSN + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; //order = 3; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + goto send; + } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD) { // 0x88 + // Read e-purse (88 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; //order = 4; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + LED_B_ON(); + goto send; + } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KC) { // 0x18 + // Read e-purse (18 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; //order = 4; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + LED_B_ON(); + goto send; + } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { // 0x05 + // Reader random and reader MAC!!! + if (simulationMode == MODE_FULLSIM) { + // 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; + CodeIClassTagAnswer(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } else { + // Not fullsim, we don't respond + // We do not know what to answer, so lets keep quiet + modulated_response = resp_sof; + modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; + + if (simulationMode == MODE_EXIT_AFTER_MAC) { + + if (DBGLEVEL == DBG_EXTENDED) { + Dbprintf("[+] 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]); + Dbprintf("[+] RDR: (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 { + Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]); + } + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); + } + exitLoop = true; + } + } + goto send; + } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { + // Reader ends the session + modulated_response = resp_sof; + modulated_response_size = 0; //order = 0; + trace_data = NULL; + trace_data_size = 0; + goto send; + } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // 0x0C + //Read block + uint16_t blk = receivedCmd[1]; + //Take the data... + memcpy(data_generic_trace, emulator + (blk << 3), 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIClassTagAnswer(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + goto send; + } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_UPDATE) { + + //Probably the reader wants to update the nonce. Let's just ignore that for now. + // OBS! If this is implemented, don't forget to regenerate the cipher_state + //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| + + //Take the data... + memcpy(data_generic_trace, receivedCmd + 2, 8); + AddCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIClassTagAnswer(trace_data, trace_data_size); + + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; +// response_delay = 4600 * 1.5; // tPROG 4-15ms + goto send; +// } else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) { // 0x84 + //Pagesel + //Pagesel enables to select a page in the selected chip memory and return its configuration block + //Chips with a single page will not answer to this command + // It appears we're fine ignoring this. + //Otherwise, we should answer 8bytes (block) + 2bytes CRC +// } else if(receivedCmd[0] == ICLASS_CMD_DETECT) { // 0x0F + } else { + //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 + // Never seen this command before + if (DBGLEVEL == DBG_EXTENDED) + print_result("[-] Unhandled command received ", receivedCmd, len); + + // Do not respond + modulated_response = resp_sof; + modulated_response_size = 0; //order = 0; + trace_data = NULL; + trace_data_size = 0; + } + +send: + /** + A legit tag has about 330us delay between reader EOT and tag SOF. + **/ + if (modulated_response_size > 0) { + t2r_stime = (GetCountSspClk() - time_0) << 4; + SendIClassAnswer(modulated_response, modulated_response_size, 0); + t2r_etime = ((GetCountSspClk() - time_0) << 4) - t2r_stime; + } + + LogTrace(receivedCmd, len, r2t_stime, r2t_etime, NULL, true); + + if (trace_data != NULL) + LogTrace(trace_data, trace_data_size, t2r_stime, t2r_etime, NULL, false); + } + + LEDsoff(); + + if (buttonPressed) + DbpString("[+] button pressed"); + + return buttonPressed; } /** - * @brief sends our simulated tag answer + * @brief sends our simulated tag answer * @param resp * @param respLen * @param delay */ static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay) { - int i = 0; - volatile uint8_t b = 0; + int i = 0; + volatile uint8_t b; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); - - AT91C_BASE_SSC->SSC_THR = 0x00; - - while (!BUTTON_PRESS()) { - - // Prevent rx holding register from overflowing - if ( (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ - b = AT91C_BASE_SSC->SSC_RHR; (void) b; - } + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){ - b = 0x00; - if ( i < respLen){ - b = resp[i]; - //Hack - //b = 0xAC; - } - i++; - AT91C_BASE_SSC->SSC_THR = b; - } -// if (i > respLen + 4) break; - if (i > respLen + 1) break; - } - return 0; + AT91C_BASE_SSC->SSC_THR = 0x00; + + while (!BUTTON_PRESS()) { + + // Prevent rx holding register from overflowing + if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) { + b = AT91C_BASE_SSC->SSC_RHR; + (void) b; + } + + // Put byte into tx holding register as soon as it is ready + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + b = 0x00; + if (i < respLen) { + b = resp[i]; + //Hack + //b = 0xAC; + } + i++; + AT91C_BASE_SSC->SSC_THR = b; + } +// if (i > respLen + 4) break; + if (i > respLen + 1) break; + } + return 0; } /// THE READER CODE @@ -1619,114 +1664,114 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay) { //----------------------------------------------------------------------------- static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) { - int c = 0; - volatile uint32_t b; - bool firstpart = true; - uint8_t sendbyte; + int c = 0; + volatile uint32_t b; + bool firstpart = true; + uint8_t sendbyte; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - AT91C_BASE_SSC->SSC_THR = 0x00; - - // make sure we timeout previous comms. - if ( *wait ) - SpinDelayUs(*wait); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; - for (;;) { + // make sure we timeout previous comms. + if (*wait) + SpinDelayUs(*wait); - WDT_HIT(); + for (;;) { - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + WDT_HIT(); - // DOUBLE THE SAMPLES! - if (firstpart) { - sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); - } else { - sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); - c++; - } + // Put byte into tx holding register as soon as it is ready + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - if (sendbyte == 0xff) - sendbyte = 0xfe; + // DOUBLE THE SAMPLES! + if (firstpart) { + sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); + } else { + sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); + c++; + } - AT91C_BASE_SSC->SSC_THR = sendbyte; - firstpart = !firstpart; + if (sendbyte == 0xff) + sendbyte = 0xfe; - if (c >= len) break; - } + AT91C_BASE_SSC->SSC_THR = sendbyte; + firstpart = !firstpart; - // Prevent rx holding register from overflowing - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = AT91C_BASE_SSC->SSC_RHR; (void)b; - } - } + if (c >= len) break; + } - if (samples) { - if (wait) - *samples = (c + *wait) << 3; - else - *samples = c << 3; - } + // Prevent rx holding register from overflowing + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + } + + if (samples) { + if (wait) + *samples = (c + *wait) << 3; + else + *samples = c << 3; + } } //----------------------------------------------------------------------------- // Prepare iClass reader command to send to FPGA //----------------------------------------------------------------------------- -void CodeIClassCommand(const uint8_t* cmd, int len) { - int i, j, k; - uint8_t b; +void CodeIClassCommand(const uint8_t *cmd, int len) { + int i, j, k; - ToSendReset(); + ToSendReset(); - // (SOC) Start of Communication: 1 out of 4 - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x0f; - ToSend[++ToSendMax] = 0x00; + // (SOC) 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++) { + // Modulate the bytes + for (i = 0; i < len; i++) { + uint8_t b = cmd[i]; + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { - if (k == (b & 3)) - ToSend[++ToSendMax] = 0xf0; - else - ToSend[++ToSendMax] = 0x00; - } - b >>= 2; - } - } + if (k == (b & 3)) + ToSend[++ToSendMax] = 0xf0; + else + ToSend[++ToSendMax] = 0x00; + } + b >>= 2; + } + } - // (EOC) End of Communication - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; + // (EOC) End of Communication + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x00; - // Convert from last character reference to length - ToSendMax++; + // Convert from last character reference to length + ToSendMax++; } -void ReaderTransmitIClass_ext(uint8_t* frame, int len, int wait) { +void ReaderTransmitIClass_ext(uint8_t *frame, int len, int wait) { - int samples = 0; + int samples = 0; - // This is tied to other size changes - CodeIClassCommand(frame, len); + // This is tied to other size changes + CodeIClassCommand(frame, len); - // Select the card - TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait); - if (trigger) - LED_A_ON(); - - rsamples += samples; - - LogTrace(frame, len, rsamples, rsamples, NULL, true); + // Select the card + TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait); + if (trigger) + LED_A_ON(); + + rsamples += samples; + + LogTrace(frame, len, rsamples, rsamples, NULL, true); } -void ReaderTransmitIClass(uint8_t* frame, int len) { - ReaderTransmitIClass_ext(frame, len, 330); +void ReaderTransmitIClass(uint8_t *frame, int len) { + ReaderTransmitIClass_ext(frame, len, 330); } //----------------------------------------------------------------------------- @@ -1734,122 +1779,120 @@ void ReaderTransmitIClass(uint8_t* frame, int len) { // 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) { - // buffer needs to be 512 bytes - // maxLen is not used... +static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { + // buffer needs to be 512 bytes + // maxLen is not used... - int c = 0; - bool skip = false; + int c = 0; + bool skip = false; - // Setup UART/DEMOD to receive - DemodInit(receivedResponse); + // Setup UART/DEMOD to receive + DemodInit(receivedResponse); - if (elapsed) *elapsed = 0; + if (elapsed) *elapsed = 0; - // 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); - SpinDelayUs(320); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments. + // 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); + SpinDelayUs(320); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments. - // clear RXRDY: + // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; - while (!BUTTON_PRESS()) { - WDT_HIT(); + while (!BUTTON_PRESS()) { + WDT_HIT(); - // keep tx buffer in a defined state anyway. - 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)++; - } + // keep tx buffer in a defined state anyway. + 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)++; + } - // Wait for byte be become available in rx holding register - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if (c >= timeout) return false; + // Wait for byte be become available in rx holding register + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + if (c >= timeout) return false; - c++; - - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - skip = !skip; - if (skip) continue; - - if (ManchesterDecoding_iclass(b & 0x0f)) { - if (samples) - *samples = c << 3; - return true; - } - } - } - return false; + c++; + + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + skip = !skip; + if (skip) continue; + + if (ManchesterDecoding_iclass(b & 0x0f)) { + if (samples) + *samples = c << 3; + return true; + } + } + } + return false; } -int ReaderReceiveIClass(uint8_t* receivedAnswer) { - int samples = 0; +int ReaderReceiveIClass(uint8_t *receivedAnswer) { + int samples = 0; - if (!GetIClassAnswer(receivedAnswer, 0, &samples, NULL)) - return false; + if (!GetIClassAnswer(receivedAnswer, 0, &samples, NULL)) + return false; - rsamples += samples; + rsamples += samples; - LogTrace(receivedAnswer, Demod.len, rsamples, rsamples, NULL, false); + LogTrace(receivedAnswer, Demod.len, rsamples, rsamples, NULL, false); - if (samples == 0) - return false; - - return Demod.len; + if (samples == 0) + return false; + + return Demod.len; } void setupIclassReader() { - LEDsoff(); + LEDsoff(); // Start from off (no field generated) // Signal field is off with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - + FpgaSetupSsc(); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Reset trace buffer - clear_trace(); - set_tracing(true); + clear_trace(); + set_tracing(true); // 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(300); - - // Start the timer - StartCountSspClk(); - + + StartCountSspClk(); + LED_A_ON(); } -bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) { - uint8_t got_n = 0; - while (retries-- > 0) { - - ReaderTransmitIClass(command, cmdsize); - - //iceman - if received size is bigger than expected, we smash the stack here - // since its called with fixed sized arrays - got_n = ReaderReceiveIClass(resp); - - // 0xBB is the internal debug separator byte.. - if ( expected_size != got_n|| (resp[0] == 0xBB || resp[7] == 0xBB || resp[2] == 0xBB)) { - //try again - continue; - } - - if (got_n == expected_size) - return true; - } - return false; +bool sendCmdGetResponseWithRetries(uint8_t *command, size_t cmdsize, uint8_t *resp, uint8_t expected_size, uint8_t retries) { + while (retries-- > 0) { + + ReaderTransmitIClass(command, cmdsize); + + //iceman - if received size is bigger than expected, we smash the stack here + // since its called with fixed sized arrays + uint8_t got_n = ReaderReceiveIClass(resp); + + // 0xBB is the internal debug separator byte.. + if (expected_size != got_n || (resp[0] == 0xBB || resp[7] == 0xBB || resp[2] == 0xBB)) { + //try again + continue; + } + + if (got_n == expected_size) + return true; + } + return false; } /** @@ -1861,555 +1904,553 @@ bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* re */ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { - // act_all... - static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; - static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; - static uint8_t select[] = { ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; + // act_all... + static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; + static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; + static uint8_t select[] = { ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; - if (use_credit_key) - readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; + if (use_credit_key) + readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; - uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - uint8_t read_status = 0; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + uint8_t read_status = 0; - // Send act_all - ReaderTransmitIClass_ext(act_all, 1, 330+160); - // Card present? - if (!ReaderReceiveIClass(resp)) return read_status;//Fail + // Send act_all + ReaderTransmitIClass_ext(act_all, 1, 330 + 160); + // Card present? + if (!ReaderReceiveIClass(resp)) return read_status;//Fail - //Send Identify - ReaderTransmitIClass(identify, 1); + //Send Identify + ReaderTransmitIClass(identify, 1); - //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - uint8_t len = ReaderReceiveIClass(resp); - if (len != 10) return read_status;//Fail + //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC + uint8_t len = ReaderReceiveIClass(resp); + if (len != 10) return read_status;//Fail - //Copy the Anti-collision CSN to our select-packet - memcpy(&select[1], resp, 8); - - //Select the card - ReaderTransmitIClass(select, sizeof(select)); - - //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC - len = ReaderReceiveIClass(resp); - if (len != 10) return read_status;//Fail + //Copy the Anti-collision CSN to our select-packet + memcpy(&select[1], resp, 8); - //Success - level 1, we got CSN - //Save CSN in response data - memcpy(card_data, resp, 8); + //Select the card + ReaderTransmitIClass(select, sizeof(select)); - //Flag that we got to at least stage 1, read CSN - read_status = 1; + //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC + len = ReaderReceiveIClass(resp); + if (len != 10) return read_status;//Fail - // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - // ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - // if (ReaderReceiveIClass(resp) == 8) { - // //Save CC (e-purse) in response data - // memcpy(card_data+8, resp, 8); - // read_status++; - // } - - bool isOK = sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, 8, 3); - if (!isOK) return read_status; - - //Save CC (e-purse) in response data - memcpy(card_data+8, resp, 8); - read_status++; - return read_status; + //Success - level 1, we got CSN + //Save CSN in response data + memcpy(card_data, resp, 8); + + //Flag that we got to at least stage 1, read CSN + read_status = 1; + + // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) + // ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + // if (ReaderReceiveIClass(resp) == 8) { + // //Save CC (e-purse) in response data + // memcpy(card_data+8, resp, 8); + // read_status++; + // } + + bool isOK = sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, 8, 3); + if (!isOK) return read_status; + + //Save CC (e-purse) in response data + memcpy(card_data + 8, resp, 8); + read_status++; + return read_status; } -uint8_t handshakeIclassTag(uint8_t *card_data){ - return handshakeIclassTag_ext(card_data, false); +uint8_t handshakeIclassTag(uint8_t *card_data) { + return handshakeIclassTag_ext(card_data, false); } // Reader iClass Anticollission // turn off afterwards void ReaderIClass(uint8_t arg0) { - uint8_t card_data[6 * 8] = {0}; - uint8_t last_csn[8] = {0,0,0,0,0,0,0,0}; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t card_data[6 * 8] = {0}; + uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t resp[ICLASS_BUFFER_SIZE]; - memset(card_data, 0xFF, sizeof(card_data)); - memset(resp, 0xFF, sizeof(resp)); - - //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; - - //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + memset(card_data, 0xFF, sizeof(card_data)); + memset(resp, 0xFF, sizeof(resp)); - int read_status = 0; - uint16_t tryCnt = 0; - uint8_t result_status = 0; - - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully - bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; // flag to not to loop continuously, looking for tag - bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key - bool flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; // flag to read block1, configuration - bool flagReadCC = arg0 & FLAG_ICLASS_READER_CC; // flag to read block2, e-purse - bool flagReadAIA = arg0 & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area + //Read conf block CRC(0x01) => 0xfa 0x22 + uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; - setupIclassReader(); + //Read App Issuer Area block CRC(0x05) => 0xde 0x64 + uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - while (!userCancelled) { + uint16_t tryCnt = 0; - WDT_HIT(); + bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; // flag to read until one tag is found successfully + bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; // flag to not to loop continuously, looking for tag + bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // flag to use credit key + bool flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; // flag to read block1, configuration + bool flagReadCC = arg0 & FLAG_ICLASS_READER_CC; // flag to read block2, e-purse + bool flagReadAIA = arg0 & FLAG_ICLASS_READER_AIA; // flag to read block5, application issuer area - // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 2) { - if (MF_DBGLEVEL > 1) DbpString("Failed to find a tag"); - break; - } - - tryCnt++; - result_status = 0; + setupIclassReader(); - read_status = handshakeIclassTag_ext(card_data, use_credit_key); + bool userCancelled = BUTTON_PRESS() || data_available(); + while (!userCancelled) { - if (read_status == 0) continue; - if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; + WDT_HIT(); - // handshakeIclass returns CSN|CC, but the actual block - // layout is CSN|CONFIG|CC, so here we reorder the data, - // moving CC forward 8 bytes - memcpy(card_data+16, card_data+8, 8); + // if only looking for one card try 2 times if we missed it the first time + if (try_once && tryCnt > 2) { + if (DBGLEVEL > 1) DbpString("Failed to find a tag"); + break; + } - //Read block 1, config - if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 5)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - if (MF_DBGLEVEL > 1) DbpString("Failed to dump config block"); - } - } + tryCnt++; + uint8_t result_status = 0; - //Read block 5, AIA - if (flagReadAIA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 5)) { - result_status |= FLAG_ICLASS_READER_AIA; - memcpy(card_data+(8*5), resp, 8); - } else { - if (MF_DBGLEVEL > 1) DbpString("Failed to dump AA block"); - } - } + int read_status = handshakeIclassTag_ext(card_data, use_credit_key); - // 0 : CSN - // 1 : Configuration - // 2 : e-purse - // 3 : kd / debit / aa2 (write-only) - // 4 : kc / credit / aa1 (write-only) - // 5 : AIA, Application issuer area - // - //Then we can 'ship' back the 6 * 8 bytes of data, - // with 0xFF:s in block 3 and 4. + if (read_status == 0) continue; + if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; + if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; - LED_B_ON(); - //Send back to client, but don't bother if we already sent this - - // only useful if looping in arm (not try_once && not abort_after_read) - if (memcmp(last_csn, card_data, 8) != 0) { - // If caller requires that we get Conf, CC, AA, continue until we got it - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("STATUS %02X | CSN %c | CONF %c | CC %c | AIA %c | ONCE %c | 1TRY %c", - result_status, - (result_status & FLAG_ICLASS_READER_CSN) ? 'Y':'N', - (result_status & FLAG_ICLASS_READER_CONF)? 'Y':'N', - (result_status & FLAG_ICLASS_READER_CC) ? 'Y':'N', - (result_status & FLAG_ICLASS_READER_AIA) ? 'Y':'N' - ); - Dbprintf(" aar %c | to %c, | uc %c | frc %c | fra %c | cc %c", - abort_after_read ? 'Y':'N', - try_once ? 'Y':'N', - use_credit_key ? 'Y':'N', - flagReadConfig ? 'Y':'N', - flagReadAIA ? 'Y':'N', - flagReadCC ? 'Y':'N' - ); - } - - bool send = (result_status & FLAG_ICLASS_READER_CSN ); - if (flagReadCC) - send |= (result_status & FLAG_ICLASS_READER_CC ); - if (flagReadAIA) - send |= (result_status & FLAG_ICLASS_READER_AIA ); - if (flagReadConfig) - send |= (result_status & FLAG_ICLASS_READER_CONF ); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SEND %c", send?'y':'n'); - - if ( send ) { - cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data) ); - if (abort_after_read) { - LED_B_OFF(); - return; - } - //Save that we already sent this.... - memcpy(last_csn, card_data, 8); - } - } - LED_B_OFF(); - userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - } - - if (userCancelled) { - cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0); - switch_off(); - } else { - cmd_send(CMD_ACK, 0, 0, 0, card_data, 0); - } + // handshakeIclass returns CSN|CC, but the actual block + // layout is CSN|CONFIG|CC, so here we reorder the data, + // moving CC forward 8 bytes + memcpy(card_data + 16, card_data + 8, 8); + + //Read block 1, config + if (flagReadConfig) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 5)) { + result_status |= FLAG_ICLASS_READER_CONF; + memcpy(card_data + 8, resp, 8); + } else { + if (DBGLEVEL > 1) DbpString("Failed to dump config block"); + } + } + + //Read block 5, AIA + if (flagReadAIA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 5)) { + result_status |= FLAG_ICLASS_READER_AIA; + memcpy(card_data + (8 * 5), resp, 8); + } else { + if (DBGLEVEL > 1) DbpString("Failed to dump AA block"); + } + } + + // 0 : CSN + // 1 : Configuration + // 2 : e-purse + // 3 : kd / debit / aa2 (write-only) + // 4 : kc / credit / aa1 (write-only) + // 5 : AIA, Application issuer area + // + //Then we can 'ship' back the 6 * 8 bytes of data, + // with 0xFF:s in block 3 and 4. + + LED_B_ON(); + //Send back to client, but don't bother if we already sent this - + // only useful if looping in arm (not try_once && not abort_after_read) + if (memcmp(last_csn, card_data, 8) != 0) { + // If caller requires that we get Conf, CC, AA, continue until we got it + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("STATUS %02X | CSN %c | CONF %c | CC %c | AIA %c | ONCE %c | 1TRY %c", + result_status, + (result_status & FLAG_ICLASS_READER_CSN) ? 'Y' : 'N', + (result_status & FLAG_ICLASS_READER_CONF) ? 'Y' : 'N', + (result_status & FLAG_ICLASS_READER_CC) ? 'Y' : 'N', + (result_status & FLAG_ICLASS_READER_AIA) ? 'Y' : 'N' + ); + Dbprintf(" aar %c | to %c, | uc %c | frc %c | fra %c | cc %c", + abort_after_read ? 'Y' : 'N', + try_once ? 'Y' : 'N', + use_credit_key ? 'Y' : 'N', + flagReadConfig ? 'Y' : 'N', + flagReadAIA ? 'Y' : 'N', + flagReadCC ? 'Y' : 'N' + ); + } + + bool send = (result_status & FLAG_ICLASS_READER_CSN); + if (flagReadCC) + send |= (result_status & FLAG_ICLASS_READER_CC); + if (flagReadAIA) + send |= (result_status & FLAG_ICLASS_READER_AIA); + if (flagReadConfig) + send |= (result_status & FLAG_ICLASS_READER_CONF); + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SEND %c", send ? 'y' : 'n'); + + if (send) { + reply_old(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + if (abort_after_read) { + LED_B_OFF(); + return; + } + //Save that we already sent this.... + memcpy(last_csn, card_data, 8); + } + } + LED_B_OFF(); + userCancelled = BUTTON_PRESS() || data_available(); + } + + if (userCancelled) { + reply_old(CMD_ACK, 0xFF, 0, 0, card_data, 0); + switch_off(); + } else { + reply_old(CMD_ACK, 0, 0, 0, card_data, 0); + } } // turn off afterwards -void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { +void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac) { - uint8_t cardsize = 0; - uint8_t mem = 0; - uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; - uint8_t card_data[USB_CMD_DATA_SIZE] = {0}; - uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + uint8_t cardsize = 0; + uint8_t mem = 0; + uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; + uint8_t card_data[PM3_CMD_DATA_SIZE] = {0}; + uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; + + static struct memory_t { + int k16; + int book; + int k2; + int lockauth; + int keyaccess; + } memory; - static struct memory_t{ - int k16; - int book; - int k2; - int lockauth; - int keyaccess; - } memory; - setupIclassReader(); - while (!BUTTON_PRESS()) { - - WDT_HIT(); - - uint8_t read_status = handshakeIclassTag(card_data); - if (read_status < 2) continue; + while (!BUTTON_PRESS()) { - //for now replay captured auth (as cc not updated) - memcpy(check+5, MAC, 4); + WDT_HIT(); - if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 5)) { - DbpString("Error: Authentication Fail!"); - continue; - } + uint8_t read_status = handshakeIclassTag(card_data); + if (read_status < 2) continue; - //first get configuration block (block 1) - read[1] = 1; - AddCrc( read+1, 1 ); + //for now replay captured auth (as cc not updated) + memcpy(check + 5, mac, 4); - if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { - DbpString("Dump config (block 1) failed"); - continue; - } + if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 5)) { + DbpString("Error: Authentication Fail!"); + continue; + } - mem = resp[5]; - memory.k16 = (mem & 0x80); - memory.book = (mem & 0x20); - memory.k2 = (mem & 0x8); - memory.lockauth = (mem & 0x2); - memory.keyaccess = (mem & 0x1); + //first get configuration block (block 1) + read[1] = 1; + AddCrc(read + 1, 1); - cardsize = memory.k16 ? 255 : 32; + if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { + DbpString("Dump config (block 1) failed"); + continue; + } - WDT_HIT(); - //Set card_data to all zeroes, we'll fill it with data - memset(card_data, 0x0, USB_CMD_DATA_SIZE); - uint8_t failedRead = 0; - uint32_t stored_data_length = 0; + mem = resp[5]; + memory.k16 = (mem & 0x80); + memory.book = (mem & 0x20); + memory.k2 = (mem & 0x8); + memory.lockauth = (mem & 0x2); + memory.keyaccess = (mem & 0x1); - //then loop around remaining blocks - for ( uint16_t block=0; block < cardsize; block++) { + cardsize = memory.k16 ? 255 : 32; - read[1] = block; - AddCrc( read+1, 1 ); + WDT_HIT(); + //Set card_data to all zeroes, we'll fill it with data + memset(card_data, 0x0, PM3_CMD_DATA_SIZE); + uint8_t failedRead = 0; + uint32_t stored_data_length = 0; - if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { - Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", - block, resp[0], resp[1], resp[2], - resp[3], resp[4], resp[5], - resp[6], resp[7] - ); + //then loop around remaining blocks + for (uint16_t block = 0; block < cardsize; block++) { - //Fill up the buffer - memcpy(card_data + stored_data_length, resp, 8); - stored_data_length += 8; - if (stored_data_length + 8 > USB_CMD_DATA_SIZE) { - //Time to send this off and start afresh - cmd_send(CMD_ACK, - stored_data_length,//data length - failedRead,//Failed blocks? - 0,//Not used ATM - card_data, - stored_data_length - ); - //reset - stored_data_length = 0; - failedRead = 0; - } - } else { - failedRead = 1; - stored_data_length += 8;//Otherwise, data becomes misaligned - Dbprintf("Failed to dump block %d", block); - } - } + read[1] = block; + AddCrc(read + 1, 1); - //Send off any remaining data - if (stored_data_length > 0) { - cmd_send(CMD_ACK, - stored_data_length,//data length - failedRead,//Failed blocks? - 0,//Not used ATM - card_data, - stored_data_length - ); - } - //If we got here, let's break - break; - } - //Signal end of transmission - cmd_send(CMD_ACK, - 0,//data length - 0,//Failed blocks? - 0,//Not used ATM - card_data, - 0 - ); - switch_off(); + if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 5)) { + Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", + block, resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7] + ); + + //Fill up the buffer + memcpy(card_data + stored_data_length, resp, 8); + stored_data_length += 8; + if (stored_data_length + 8 > PM3_CMD_DATA_SIZE) { + //Time to send this off and start afresh + reply_old(CMD_ACK, + stored_data_length,//data length + failedRead,//Failed blocks? + 0,//Not used ATM + card_data, + stored_data_length + ); + //reset + stored_data_length = 0; + failedRead = 0; + } + } else { + failedRead = 1; + stored_data_length += 8;//Otherwise, data becomes misaligned + Dbprintf("Failed to dump block %d", block); + } + } + + //Send off any remaining data + if (stored_data_length > 0) { + reply_old(CMD_ACK, + stored_data_length,//data length + failedRead,//Failed blocks? + 0,//Not used ATM + card_data, + stored_data_length + ); + } + //If we got here, let's break + break; + } + //Signal end of transmission + reply_old(CMD_ACK, + 0,//data length + 0,//Failed blocks? + 0,//Not used ATM + card_data, + 0 + ); + switch_off(); } // not used. ?!? ( CMD_ICLASS_READCHECK) // turn off afterwards -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) { - uint8_t readcheck[] = { keyType, blockNo }; - uint8_t resp[] = {0,0,0,0,0,0,0,0}; - size_t isOK = 0; - isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 6); - cmd_send(CMD_ACK,isOK,0,0,0,0); - switch_off(); +void iClass_ReadCheck(uint8_t blockno, uint8_t keytype) { + uint8_t readcheck[] = { keytype, blockno }; + uint8_t resp[] = {0, 0, 0, 0, 0, 0, 0, 0}; + size_t isOK = 0; + isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 6); + reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); + switch_off(); } -// used with function select_and_auth (cmdhficlass.c) +// used with function select_and_auth (cmdhficlass.c) // which needs to authenticate before doing more things like read/write void iClass_Authentication(uint8_t *mac) { - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t resp[ICLASS_BUFFER_SIZE]; - // copy MAC to check command (readersignature) - check[5] = mac[0]; - check[6] = mac[1]; - check[7] = mac[2]; - check[8] = mac[3]; - //memcpy(check+5, mac, 4); - - // 6 retries - bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6); - cmd_send(CMD_ACK,isOK,0,0,0,0); + // copy MAC to check command (readersignature) + check[5] = mac[0]; + check[6] = mac[1]; + check[7] = mac[2]; + check[8] = mac[3]; + //memcpy(check+5, mac, 4); + + // 6 retries + bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6); + reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); } typedef struct iclass_premac { - uint8_t mac[4]; + uint8_t mac[4]; } iclass_premac_t; /* this function works on the following assumptions. -* - one select first, to get CSN / CC (e-purse) +* - one select first, to get CSN / CC (e-purse) * - calculate before diversified keys and precalc mac based on CSN/KEY. * - data in contains of diversified keys, mac * - key loop only test one type of authtication key. Ie two calls needed * to cover debit and credit key. (AA1/AA2) */ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { - uint8_t i = 0, isOK = 0; - uint8_t lastChunk = ((arg0 >> 8) & 0xFF); - bool use_credit_key =((arg0 >> 16) & 0xFF); - uint8_t keyCount = arg1 & 0xFF; - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; - uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; + uint8_t i = 0, isOK = 0; + uint8_t lastChunk = ((arg0 >> 8) & 0xFF); + bool use_credit_key = ((arg0 >> 16) & 0xFF); + uint8_t keyCount = arg1 & 0xFF; + uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t resp[ICLASS_BUFFER_SIZE]; + uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; - if (use_credit_key) - readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; - - // select card / e-purse - uint8_t card_data[6 * 8] = {0}; - - iclass_premac_t *keys = (iclass_premac_t *)datain; - - LED_A_ON(); - - switch_off(); - SpinDelay(20); - - setupIclassReader(); + if (use_credit_key) + readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; - int read_status = 0; - uint8_t startup_limit = 10; - while ( read_status != 2) { - - if (BUTTON_PRESS() && !usb_poll_validate_length()) goto out; - - read_status = handshakeIclassTag_ext(card_data, use_credit_key); - if ( startup_limit-- == 0 ) { - Dbprintf("[-] Handshake status | %d (fail 10)", read_status); - isOK = 99; - goto out; - } - }; - // since handshakeIclassTag_ext call sends s readcheck, we start with sending first response. - - // Keychunk loop - for (i = 0; i < keyCount; i++) { - - // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && !usb_poll_validate_length()) break; + // select card / e-purse + uint8_t card_data[6 * 8] = {0}; - WDT_HIT(); - LED_B_ON(); - - // copy MAC to check command (readersignature) - check[5] = keys[i].mac[0]; - check[6] = keys[i].mac[1]; - check[7] = keys[i].mac[2]; - check[8] = keys[i].mac[3]; - - // expect 4bytes, 3 retries times.. - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 3); - if ( isOK ) - goto out; - - SpinDelayUs(400); //iClass (iso15693-2) should timeout after 330us. + iclass_premac_t *keys = (iclass_premac_t *)datain; - // Auth Sequence MUST begin with reading e-purse. (block2) - // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - - LED_B_OFF(); - } - -out: - // send keyindex. - cmd_send(CMD_ACK, isOK, i, 0, 0, 0); - - if ( isOK >= 1 || lastChunk ) { - switch_off(); - LED_A_OFF(); - } - - LED_B_OFF(); - LED_C_OFF(); + LED_A_ON(); + + switch_off(); + SpinDelay(20); + + setupIclassReader(); + + int read_status = 0; + uint8_t startup_limit = 10; + while (read_status != 2) { + + if (BUTTON_PRESS() && !data_available()) goto out; + + read_status = handshakeIclassTag_ext(card_data, use_credit_key); + if (startup_limit-- == 0) { + Dbprintf("[-] Handshake status | %d (fail 10)", read_status); + isOK = 99; + goto out; + } + }; + // since handshakeIclassTag_ext call sends s readcheck, we start with sending first response. + + // Keychunk loop + for (i = 0; i < keyCount; i++) { + + // Allow button press / usb cmd to interrupt device + if (BUTTON_PRESS() && !data_available()) break; + + WDT_HIT(); + LED_B_ON(); + + // copy MAC to check command (readersignature) + check[5] = keys[i].mac[0]; + check[6] = keys[i].mac[1]; + check[7] = keys[i].mac[2]; + check[8] = keys[i].mac[3]; + + // expect 4bytes, 3 retries times.. + isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 3); + if (isOK) + goto out; + + SpinDelayUs(400); //iClass (iso15693-2) should timeout after 330us. + + // Auth Sequence MUST begin with reading e-purse. (block2) + // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); + + LED_B_OFF(); + } + +out: + // send keyindex. + reply_mix(CMD_ACK, isOK, i, 0, 0, 0); + + if (isOK >= 1 || lastChunk) { + switch_off(); + LED_A_OFF(); + } + + LED_B_OFF(); + LED_C_OFF(); } // Tries to read block. // retries 10times. -bool iClass_ReadBlock(uint8_t blockNo, uint8_t *data, uint8_t len) { - uint8_t resp[10]; - uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; - AddCrc( cmd+1, 1 ); - // expect size 10, retry 5times - bool isOK = sendCmdGetResponseWithRetries(cmd, sizeof(cmd), resp, 10, 5); - memcpy(data, resp, len); - return isOK; +bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len) { + uint8_t resp[10]; + uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; + AddCrc(cmd + 1, 1); + // expect size 10, retry 5times + bool isOK = sendCmdGetResponseWithRetries(cmd, sizeof(cmd), resp, 10, 5); + memcpy(data, resp, len); + return isOK; } // turn off afterwards // readblock 8 + 2. only want 8. void iClass_ReadBlk(uint8_t blockno) { - uint8_t data[] = {0,0,0,0,0,0,0,0,0,0}; - bool isOK = iClass_ReadBlock(blockno, data, sizeof(data)); - cmd_send(CMD_ACK, isOK, 0, 0, data, sizeof(data)); - switch_off(); + uint8_t data[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + bool isOK = iClass_ReadBlock(blockno, data, sizeof(data)); + reply_mix(CMD_ACK, isOK, 0, 0, data, sizeof(data)); + switch_off(); } // turn off afterwards void iClass_Dump(uint8_t blockno, uint8_t numblks) { - uint8_t blockdata[] = {0,0,0,0,0,0,0,0,0,0}; - bool isOK = false; - uint8_t blkCnt = 0; + uint8_t blockdata[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + bool isOK = false; + uint8_t blkCnt = 0; - BigBuf_free(); - uint8_t *dataout = BigBuf_malloc(255*8); - if (dataout == NULL){ - DbpString("[!] out of memory"); - OnError(1); - return; - } - // fill mem with 0xFF - memset(dataout, 0xFF, 255*8); + BigBuf_free(); + uint8_t *dataout = BigBuf_malloc(255 * 8); + if (dataout == NULL) { + DbpString("[!] out of memory"); + OnError(1); + return; + } + // fill mem with 0xFF + memset(dataout, 0xFF, 255 * 8); - for (;blkCnt < numblks; blkCnt++) { - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); - - // 0xBB is the internal debug separator byte.. - if (!isOK || (blockdata[0] == 0xBB || blockdata[7] == 0xBB || blockdata[2] == 0xBB)) { //try again - isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); - if (!isOK) { - Dbprintf("[!] block %02X failed to read", blkCnt + blockno); - break; - } - } - memcpy(dataout + (blkCnt * 8), blockdata, 8); - } - //return pointer to dump memory in arg3 - cmd_send(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); - switch_off(); - BigBuf_free(); + for (; blkCnt < numblks; blkCnt++) { + isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); + + // 0xBB is the internal debug separator byte.. + if (!isOK || (blockdata[0] == 0xBB || blockdata[7] == 0xBB || blockdata[2] == 0xBB)) { //try again + isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata)); + if (!isOK) { + Dbprintf("[!] block %02X failed to read", blkCnt + blockno); + break; + } + } + memcpy(dataout + (blkCnt * 8), blockdata, 8); + } + //return pointer to dump memory in arg3 + reply_mix(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); + switch_off(); + BigBuf_free(); } -bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { +bool iClass_WriteBlock_ext(uint8_t blockno, uint8_t *data) { - uint8_t resp[] = {0,0,0,0,0,0,0,0,0,0}; - uint8_t write[] = { ICLASS_CMD_UPDATE, blockNo, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - memcpy(write+2, data, 12); // data + mac - AddCrc(write+1, 13); + uint8_t resp[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t write[] = { ICLASS_CMD_UPDATE, blockno, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + memcpy(write + 2, data, 12); // data + mac + AddCrc(write + 1, 13); - bool isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5); - if (isOK) { //if reader responded correctly + bool isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5); + if (isOK) { //if reader responded correctly - //if response is not equal to write values - if (memcmp(write + 2, resp, 8)) { + //if response is not equal to write values + if (memcmp(write + 2, resp, 8)) { - //if not programming key areas (note key blocks don't get programmed with actual key data it is xor data) - if (blockNo != 3 && blockNo != 4) { - isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5); - } - } - } - return isOK; + //if not programming key areas (note key blocks don't get programmed with actual key data it is xor data) + if (blockno != 3 && blockno != 4) { + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5); + } + } + } + return isOK; } // turn off afterwards -void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { - bool isOK = iClass_WriteBlock_ext(blockNo, data); - cmd_send(CMD_ACK,isOK,0,0,0,0); - switch_off(); +void iClass_WriteBlock(uint8_t blockno, uint8_t *data) { + bool isOK = iClass_WriteBlock_ext(blockno, data); + reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); + switch_off(); } // turn off afterwards void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { - int i, written = 0; - int total_block = (endblock - startblock) + 1; - for (i = 0; i < total_block; i++){ - // block number - if (iClass_WriteBlock_ext(i + startblock, data + ( i*12 ) )){ - Dbprintf("Write block [%02x] successful", i + startblock); - written++; - } else { - if (iClass_WriteBlock_ext(i + startblock, data + ( i*12 ) )){ - Dbprintf("Write block [%02x] successful", i + startblock); - written++; - } else { - Dbprintf("Write block [%02x] failed", i + startblock); - } - } - } - if (written == total_block) - DbpString("Clone complete"); - else - DbpString("Clone incomplete"); + int i, written = 0; + int total_block = (endblock - startblock) + 1; + for (i = 0; i < total_block; i++) { + // block number + if (iClass_WriteBlock_ext(i + startblock, data + (i * 12))) { + Dbprintf("Write block [%02x] successful", i + startblock); + written++; + } else { + if (iClass_WriteBlock_ext(i + startblock, data + (i * 12))) { + Dbprintf("Write block [%02x] successful", i + startblock); + written++; + } else { + Dbprintf("Write block [%02x] failed", i + startblock); + } + } + } + if (written == total_block) + DbpString("Clone complete"); + else + DbpString("Clone incomplete"); - cmd_send(CMD_ACK,1,0,0,0,0); - switch_off(); -} \ No newline at end of file + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + switch_off(); +} diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f6be25a50..b5e612ec9 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -14,20 +14,19 @@ #define MAX_ISO14A_TIMEOUT 524288 static uint32_t iso14a_timeout; +uint8_t colpos = 0; int rsamples = 0; - uint8_t trigger = 0; // the block number for the ISO14443-4 PCB static uint8_t iso14_pcb_blocknum = 0; -static uint8_t* free_buffer_pointer; // // ISO14443 timing: // // 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) +// 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; // @@ -39,8 +38,8 @@ static uint8_t* free_buffer_pointer; // 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 @@ -50,17 +49,6 @@ static uint8_t* free_buffer_pointer; // 1 tick to assign mod_sig_coil #define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) -// When the PM acts as tag and is receiving it takes -// 2 ticks delay in the RF part (for the first falling edge), -// 3 ticks for the A/D conversion, -// 8 ticks on average until the start of the SSC transfer, -// 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 -#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 @@ -82,16 +70,16 @@ 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: @@ -103,52 +91,55 @@ static uint32_t LastProxToAirDuration; // 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 +// Sequence COLL: 11111111 load modulation over the full bitlenght. +// Tricks the reader to think that multiple cards answer (at least one card with 1 and at least one card with 0). // READER TO CARD - miller // 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_COLL 0xff +#define SEC_X 0x0c +#define SEC_Y 0x00 +#define SEC_Z 0xc0 void iso14a_set_trigger(bool enable) { - trigger = enable; + trigger = enable; } void iso14a_set_timeout(uint32_t timeout) { - iso14a_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2; + iso14a_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) + 2; } uint32_t iso14a_get_timeout(void) { - return iso14a_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2; + return iso14a_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / (16 * 8) - 2; } //----------------------------------------------------------------------------- // Generate the parity value for a byte sequence //----------------------------------------------------------------------------- -void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) { - uint16_t paritybit_cnt = 0; - uint16_t paritybyte_cnt = 0; - uint8_t parityBits = 0; +void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par) { + uint16_t paritybit_cnt = 0; + uint16_t paritybyte_cnt = 0; + uint8_t parityBits = 0; - 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++; - } - } + for (uint16_t i = 0; i < len; 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++; + } + } - // save remaining parity bits - par[paritybyte_cnt] = parityBits; + // save remaining parity bits + par[paritybyte_cnt] = parityBits; } @@ -157,14 +148,14 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) { //============================================================================= // 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. //----------------------------------------------------------------------------- @@ -177,155 +168,155 @@ static tUart Uart; // 0111 - a 2 tick wide pause shifted left // 1001 - a 2 tick wide pause shifted right const bool Mod_Miller_LUT[] = { - false, true, false, true, false, false, false, true, - false, true, false, false, false, false, false, false + false, true, false, true, false, false, false, true, + false, true, false, false, false, false, false, false }; #define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x000000F0) >> 4]) #define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x0000000F)]) -tUart* GetUart() { - return &Uart; +tUart *GetUart() { + return &Uart; } void UartReset(void) { - 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 - Uart.startTime = 0; - Uart.endTime = 0; - Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits - Uart.posCnt = 0; - Uart.syncBit = 9999; + 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 + Uart.startTime = 0; + Uart.endTime = 0; + Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.posCnt = 0; + Uart.syncBit = 9999; } -void UartInit(uint8_t *data, uint8_t *parity) { - Uart.output = data; - Uart.parity = parity; - UartReset(); +void UartInit(uint8_t *data, uint8_t *par) { + Uart.output = data; + Uart.parity = par; + UartReset(); } // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time 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 - - // 00x11111 2|3 ticks pause followed by 6|5 ticks unmodulated Sequence Z (a "0" or "start of communication") - // 11111111 8 ticks unmodulation Sequence Y (a "0" or "end of communication" or "no information") - // 111100x1 4 ticks unmodulated followed by 2|3 ticks pause Sequence X (a "1") + Uart.fourBits = (Uart.fourBits << 8) | bit; - // 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 ...xx1111 11111111 00x11111xxxxxx... 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.state == STATE_UNSYNCD) { // not yet synced + Uart.syncBit = 9999; // not set - 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; - } - } else { + // 00x11111 2|3 ticks pause followed by 6|5 ticks unmodulated Sequence Z (a "0" or "start of communication") + // 11111111 8 ticks unmodulation Sequence Y (a "0" or "end of communication" or "no information") + // 111100x1 4 ticks unmodulated followed by 2|3 ticks pause Sequence X (a "1") - if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { - if (IsMillerModulationNibble2(Uart.fourBits >> 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 - UartReset(); - } else { - Uart.bitCount++; - 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) - 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; - } - } - } - } - } else { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" - Uart.bitCount++; - 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) - 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.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 - 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 - 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) - 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 + // 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 ...xx1111 11111111 00x11111xxxxxx... 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; + } + } else { + + if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { + if (IsMillerModulationNibble2(Uart.fourBits >> 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 + UartReset(); + } else { + Uart.bitCount++; + 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) + 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; + } + } + } + } + } else { + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" + Uart.bitCount++; + 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) + 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.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 + 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 + 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) + 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 } //============================================================================= @@ -337,10 +328,10 @@ 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) tDemod Demod; @@ -348,126 +339,126 @@ 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)]) -tDemod* GetDemod() { - return &Demod; +tDemod *GetDemod() { + return &Demod; } void DemodReset(void) { - 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.highCnt = 0; - Demod.startTime = 0; - Demod.endTime = 0; - Demod.bitCount = 0; - Demod.syncBit = 0xFFFF; - Demod.samples = 0; + 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.highCnt = 0; + Demod.startTime = 0; + Demod.endTime = 0; + Demod.bitCount = 0; + Demod.syncBit = 0xFFFF; + Demod.samples = 0; } -void DemodInit(uint8_t *data, uint8_t *parity) { - Demod.output = data; - Demod.parity = parity; - DemodReset(); +void DemodInit(uint8_t *data, uint8_t *par) { + Demod.output = data; + Demod.parity = par; + DemodReset(); } // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time 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) { + Demod.twoBits = (Demod.twoBits << 8) | bit; - 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; - 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; - else if ((Demod.twoBits & 0x0770) == 0x0700) Demod.syncBit = 3; - else if ((Demod.twoBits & 0x03B8) == 0x0380) Demod.syncBit = 2; - else if ((Demod.twoBits & 0x01DC) == 0x01C0) Demod.syncBit = 1; - else if ((Demod.twoBits & 0x00EE) == 0x00E0) Demod.syncBit = 0; - 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.state = DEMOD_MANCHESTER_DATA; - } - } - } else { + if (Demod.state == DEMOD_UNSYNCD) { - 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 - 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.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.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 - 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.output[Demod.len++] = (Demod.shiftReg & 0xff); - 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 - 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 - DemodReset(); - } - } - } - } - return false; // not finished yet, need more data + 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; + 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; + else if ((Demod.twoBits & 0x0770) == 0x0700) Demod.syncBit = 3; + else if ((Demod.twoBits & 0x03B8) == 0x0380) Demod.syncBit = 2; + else if ((Demod.twoBits & 0x01DC) == 0x01C0) Demod.syncBit = 1; + else if ((Demod.twoBits & 0x00EE) == 0x00E0) Demod.syncBit = 0; + 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.state = DEMOD_MANCHESTER_DATA; + } + } + } else { + + 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 + 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.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.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 + 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.output[Demod.len++] = (Demod.shiftReg & 0xff); + 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 + 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 + DemodReset(); + } + } + } + } + return false; // not finished yet, need more data } //============================================================================= @@ -482,254 +473,270 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t // "hf 14a sniff" //----------------------------------------------------------------------------- void RAMFUNC SniffIso14443a(uint8_t param) { - LEDsoff(); - // param: - // bit 0 - trigger from first card answer - // bit 1 - trigger from first reader 7-bit request - iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - // 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 *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); - - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - uint8_t *data = dmaBuf; + LEDsoff(); + // param: + // bit 0 - trigger from first card answer + // bit 1 - trigger from first reader 7-bit request + iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); - 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(receivedResp, receivedRespPar); - - // Set up the demodulator for the reader -> tag commands - UartInit(receivedCmd, receivedCmdPar); - - // Setup and start DMA. - if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE) ){ - if (MF_DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); - return; - } - - // 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); - - uint32_t rsamples = 0; + // Allocate memory from BigBuf for some buffers + // free all previous allocations first + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); - DbpString("Starting to sniff"); - - // loop and listen - while (!BUTTON_PRESS()) { + // 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 *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); + + // The DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + uint8_t *data = dmaBuf; + + uint8_t previous_data = 0; + int maxDataLen = 0, dataLen; + bool TagIsActive = false; + bool ReaderIsActive = false; + + // Set up the demodulator for tag -> reader responses. + DemodInit(receivedResp, receivedRespPar); + + // Set up the demodulator for the reader -> tag commands + UartInit(receivedCmd, receivedCmdPar); + + DbpString("Starting to sniff"); + + // Setup and start DMA. + if (!FpgaSetupSscDma((uint8_t *) dmaBuf, DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return; + } + + // 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); + + uint32_t rx_samples = 0; + + // loop and listen + while (!BUTTON_PRESS()) { WDT_HIT(); LED_A_ON(); - int register readBufDataP = data - dmaBuf; - int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; - if (readBufDataP <= dmaBufDataP) - dataLen = dmaBufDataP - readBufDataP; - else - dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; - - // test for length of buffer - if (dataLen > maxDataLen) { - maxDataLen = dataLen; - if (dataLen > (9 * DMA_BUFFER_SIZE / 10)) { - Dbprintf("[!] blew circular buffer! | datalen %u", dataLen); - break; - } - } - if (dataLen < 1) continue; + int register readBufDataP = data - dmaBuf; + int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; + if (readBufDataP <= dmaBufDataP) + dataLen = dmaBufDataP - readBufDataP; + else + dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; - // primary buffer was stopped( <-- we lost data! - if (!AT91C_BASE_PDC_SSC->PDC_RCR) { - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; - Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary - } - // secondary buffer sets as primary, secondary buffer was stopped - if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; - } + // test for length of buffer + if (dataLen > maxDataLen) { + maxDataLen = dataLen; + if (dataLen > (9 * DMA_BUFFER_SIZE / 10)) { + Dbprintf("[!] blew circular buffer! | datalen %u", dataLen); + break; + } + } + if (dataLen < 1) continue; - LED_A_OFF(); - - // Need two samples to feed Miller and Manchester-Decoder - if (rsamples & 0x01) { + // primary buffer was stopped( <-- we lost data! + if (!AT91C_BASE_PDC_SSC->PDC_RCR) { + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; + Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary + } + // secondary buffer sets as primary, secondary buffer was stopped + if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } - 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(); + LED_A_OFF(); - // check - if there is a short 7bit request from reader - if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = true; + // Need two samples to feed Miller and Manchester-Decoder + if (rx_samples & 0x01) { - 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; - } - /* ready to receive another command. */ - UartReset(); - /* 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 (!TagIsActive) { // no need to try decoding reader data if the tag is sending + uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); + if (MillerDecoding(readerdata, (rx_samples - 1) * 4)) { + LED_C_ON(); - // no need to try decoding tag data if the reader is sending - and we cannot afford the time - if (!ReaderIsActive) { - uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); - if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { - LED_B_ON(); + // check - if there is a short 7bit request from reader + if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = true; - if (!LogTrace(receivedResp, - Demod.len, - Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.parity, - false)) break; + 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; + } + /* ready to receive another command. */ + UartReset(); + /* 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 ((!triggered) && (param & 0x01)) triggered = true; + // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { + uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); + if (ManchesterDecoding(tagdata, 0, (rx_samples - 1) * 4)) { + LED_B_ON(); - // ready to receive another response. - DemodReset(); - // reset the Miller decoder including its (now outdated) input buffer - UartReset(); - //UartInit(receivedCmd, receivedCmdPar); - LED_C_OFF(); - } - TagIsActive = (Demod.state != DEMOD_UNSYNCD); - } - } + if (!LogTrace(receivedResp, + Demod.len, + Demod.startTime * 16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.endTime * 16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + Demod.parity, + false)) break; - previous_data = *data; - rsamples++; - data++; - if (data == dmaBuf + DMA_BUFFER_SIZE) { - data = dmaBuf; - } - } // end main loop + if ((!triggered) && (param & 0x01)) triggered = true; - if (MF_DBGLEVEL >= 1) { - 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]); - } - switch_off(); + // ready to receive another response. + DemodReset(); + // reset the Miller decoder including its (now outdated) input buffer + UartReset(); + //UartInit(receivedCmd, receivedCmdPar); + LED_C_OFF(); + } + TagIsActive = (Demod.state != DEMOD_UNSYNCD); + } + } + + previous_data = *data; + rx_samples++; + data++; + if (data == dmaBuf + DMA_BUFFER_SIZE) { + data = dmaBuf; + } + } // end main loop + + if (DBGLEVEL >= DBG_ERROR) { + Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); + Dbprintf("traceLen=" _YELLOW_("%d")", Uart.output[0]="_YELLOW_("%08x"), BigBuf_get_traceLen(), (uint32_t)Uart.output[0]); + } + switch_off(); } //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) { - ToSendReset(); +static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par, bool collision) { - // Correction bit, might be removed when not needed - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(1); // 1 - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - - // Send startbit - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; + //uint8_t localCol = 0; + ToSendReset(); - for(uint16_t i = 0; i < len; i++) { - uint8_t b = cmd[i]; + // Correction bit, might be removed when not needed + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(1); // <----- + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); - // Data bits - for(uint16_t j = 0; j < 8; j++) { - if(b & 1) { - ToSend[++ToSendMax] = SEC_D; - } else { - ToSend[++ToSendMax] = SEC_E; - } - b >>= 1; - } + // Send startbit + ToSend[++ToSendMax] = SEC_D; + LastProxToAirDuration = 8 * ToSendMax - 4; - // Get the parity bit - if (parity[i>>3] & (0x80>>(i&0x0007))) { - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; - } else { - ToSend[++ToSendMax] = SEC_E; - LastProxToAirDuration = 8 * ToSendMax; - } - } + for (uint16_t i = 0; i < len; i++) { + uint8_t b = cmd[i]; - // Send stopbit - ToSend[++ToSendMax] = SEC_F; + // Data bits + for (uint16_t j = 0; j < 8; j++) { + //if (collision && (localCol >= colpos)){ + if (collision) { + ToSend[++ToSendMax] = SEC_COLL; + //localCol++; + } else { + if (b & 1) { + ToSend[++ToSendMax] = SEC_D; + } else { + ToSend[++ToSendMax] = SEC_E; + } + b >>= 1; + } + } - // Convert from last byte pos to length - ToSendMax++; + if (collision) { + ToSend[++ToSendMax] = SEC_COLL; + LastProxToAirDuration = 8 * ToSendMax; + } else { + // Get the parity bit + if (par[i >> 3] & (0x80 >> (i & 0x0007))) { + ToSend[++ToSendMax] = SEC_D; + LastProxToAirDuration = 8 * ToSendMax - 4; + } else { + ToSend[++ToSendMax] = SEC_E; + LastProxToAirDuration = 8 * ToSendMax; + } + } + } + + // Send stopbit + ToSend[++ToSendMax] = SEC_F; + + // Convert from last byte pos to length + ToSendMax++; } +static void CodeIso14443aAsTagEx(const uint8_t *cmd, uint16_t len, bool collision) { + uint8_t par[MAX_PARITY_SIZE] = {0}; + GetParity(cmd, len, par); + CodeIso14443aAsTagPar(cmd, len, par, collision); +} static void CodeIso14443aAsTag(const uint8_t *cmd, uint16_t len) { - uint8_t par[MAX_PARITY_SIZE] = {0}; - GetParity(cmd, len, par); - CodeIso14443aAsTagPar(cmd, len, par); + CodeIso14443aAsTagEx(cmd, len, false); } static void Code4bitAnswerAsTag(uint8_t cmd) { - uint8_t b = cmd; + uint8_t b = cmd; - ToSendReset(); + ToSendReset(); - // Correction bit, might be removed when not needed - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(1); // 1 - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); + // Correction bit, might be removed when not needed + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(1); // 1 + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); - // Send startbit - ToSend[++ToSendMax] = SEC_D; + // Send startbit + ToSend[++ToSendMax] = SEC_D; - for(uint8_t i = 0; i < 4; i++) { - if(b & 1) { - ToSend[++ToSendMax] = SEC_D; - LastProxToAirDuration = 8 * ToSendMax - 4; - } else { - ToSend[++ToSendMax] = SEC_E; - LastProxToAirDuration = 8 * ToSendMax; - } - b >>= 1; - } + for (uint8_t i = 0; i < 4; i++) { + if (b & 1) { + ToSend[++ToSendMax] = SEC_D; + LastProxToAirDuration = 8 * ToSendMax - 4; + } else { + ToSend[++ToSendMax] = SEC_E; + LastProxToAirDuration = 8 * ToSendMax; + } + b >>= 1; + } - // Send stopbit - ToSend[++ToSendMax] = SEC_F; + // Send stopbit + ToSend[++ToSendMax] = SEC_F; - // Convert from last byte pos to length - ToSendMax++; + // Convert from last byte pos to length + ToSendMax++; } //----------------------------------------------------------------------------- @@ -737,7 +744,7 @@ static void Code4bitAnswerAsTag(uint8_t cmd) { // stop when button is pressed // or return TRUE when command is captured //----------------------------------------------------------------------------- -int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) { +static bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, 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 @@ -745,78 +752,275 @@ int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) 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); + UartInit(received, par); - // clear RXRDY: + // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; - while (!BUTTON_PRESS()) { + uint16_t check = 0; + + for (;;) { + if (check == 1000) { + if (BUTTON_PRESS() || data_available()) + return false; + check = 0; + } + ++check; WDT_HIT(); 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 true; - } - } + if (MillerDecoding(b, 0)) { + *len = Uart.len; + return true; + } + } } - return false; + return false; } -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) - // 18 parity bits - // 2 Start and stop - // 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA) - // 1 just for the case - // ----------- + - // 166 bytes, since every bit that needs to be send costs us a byte - // - // Prepare the tag modulation bits from the message - CodeIso14443aAsTag(response_info->response,response_info->response_n); +static 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) + // 18 parity bits + // 2 Start and stop + // 1 Correction bit (Answer in 1172 or 1236 periods, see FPGA) + // 1 just for the case + // ----------- + + // 166 bytes, since every bit that needs to be send costs us a byte + // + // Prepare the tag modulation bits from the message + 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; - } + // 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; + } - // Copy the byte array, used for this modulation to the buffer position - memcpy(response_info->modulation,ToSend,ToSendMax); + // Copy the byte array, used for this modulation to the buffer position + 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; + // 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 -// -> need 273 bytes buffer -// 44 * 8 data bits, 44 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits --370 -// 47 * 8 data bits, 47 * 1 parity bits, 10 start bits, 10 stop bits, 10 correction bits -#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 453 +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 = free_buffer_pointer; + // Retrieve and store the current buffer index + response_info->modulation = *buffer; - // Determine the maximum size we can use from our buffer - size_t max_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; + // 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; + } else { + return false; + } +} - // Forward the prepare tag modulation function to the inner function - if (prepare_tag_modulation(response_info, max_buffer_size)) { - // Update the free buffer offset - free_buffer_pointer += ToSendMax; - return true; - } else { - return false; - } +static bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_info_t **responses, uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) { + uint8_t sak = 0; + // The first response contains the ATQA (note: bytes are transmitted in reverse order). + static uint8_t rATQA[2] = { 0x00 }; + // The second response contains the (mandatory) first 24 bits of the UID + static uint8_t rUIDc1[5] = { 0x00 }; + // For UID size 7, + static uint8_t rUIDc2[5] = { 0x00 }; + // Prepare the mandatory SAK (for 4 and 7 byte UID) + static uint8_t rSAKc1[3] = { 0x00 }; + // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit + static uint8_t rSAKc2[3] = { 0x00 }; + // dummy ATS (pseudo-ATR), answer to RATS + static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; + // GET_VERSION response for EV1/NTAG + static uint8_t rVERSION[10] = { 0x00 }; + // READ_SIG response for EV1/NTAG + static uint8_t rSIGN[34] = { 0x00 }; + + switch (tagType) { + case 1: { // MIFARE Classic 1k + rATQA[0] = 0x04; + sak = 0x08; + } + break; + case 2: { // MIFARE Ultralight + rATQA[0] = 0x44; + sak = 0x00; + // some first pages of UL/NTAG dump is special data + mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); + *pages = MAX(mfu_header->pages, 15); + } + break; + case 3: { // MIFARE DESFire + rATQA[0] = 0x04; + rATQA[1] = 0x03; + sak = 0x20; + } + break; + case 4: { // ISO/IEC 14443-4 - javacard (JCOP) + rATQA[0] = 0x04; + sak = 0x28; + } + break; + case 5: { // MIFARE TNP3XXX + rATQA[0] = 0x01; + rATQA[1] = 0x0f; + sak = 0x01; + } + break; + case 6: { // MIFARE Mini 320b + rATQA[0] = 0x44; + sak = 0x09; + } + break; + case 7: { // NTAG + rATQA[0] = 0x44; + sak = 0x00; + // some first pages of UL/NTAG dump is special data + mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); + *pages = MAX(mfu_header->pages, 19); + // counters and tearing flags + for (int i = 0; i < 3; i++) { + counters[i] = le24toh(mfu_header->counter_tearing[i]); + tearings[i] = mfu_header->counter_tearing[i][3]; + } + // GET_VERSION + memcpy(rVERSION, mfu_header->version, 8); + AddCrc14A(rVERSION, sizeof(rVERSION) - 2); + // READ_SIG + memcpy(rSIGN, mfu_header->signature, 32); + AddCrc14A(rSIGN, sizeof(rSIGN) - 2); + } + break; + case 8: { // MIFARE Classic 4k + rATQA[0] = 0x02; + sak = 0x18; + } + break; + case 9 : { // FM11RF005SH (Shanghai Metro) + rATQA[0] = 0x03; + rATQA[1] = 0x00; + sak = 0x0A; + } + break; + default: { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Error: unkown tagtype (%d)", tagType); + return false; + } + break; + } + + // if uid not supplied then get from emulator memory + if (data[0] == 0 || (flags & FLAG_UID_IN_EMUL) == FLAG_UID_IN_EMUL) { + if (tagType == 2 || tagType == 7) { + uint16_t start = MFU_DUMP_PREFIX_LENGTH; + uint8_t emdata[8]; + emlGetMemBt(emdata, start, sizeof(emdata)); + memcpy(data, emdata, 3); // uid bytes 0-2 + memcpy(data + 3, emdata + 4, 4); // uid bytes 3-7 + flags |= FLAG_7B_UID_IN_DATA; + } else { + emlGetMemBt(data, 0, 4); + flags |= FLAG_4B_UID_IN_DATA; + } + } + + if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { + rUIDc1[0] = 0x88; // Cascade Tag marker + rUIDc1[1] = data[0]; + rUIDc1[2] = data[1]; + rUIDc1[3] = data[2]; + + rUIDc2[0] = data[3]; + rUIDc2[1] = data[4]; + rUIDc2[2] = data[5]; + rUIDc2[3] = data[6]; + rUIDc2[4] = rUIDc2[0] ^ rUIDc2[1] ^ rUIDc2[2] ^ rUIDc2[3]; + + // Configure the ATQA and SAK accordingly + rATQA[0] |= 0x40; + sak |= 0x04; + + *cuid = bytes_to_num(data + 3, 4); + } else if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { + memcpy(rUIDc1, data, 4); + // Configure the ATQA and SAK accordingly + rATQA[0] &= 0xBF; + sak &= 0xFB; + *cuid = bytes_to_num(data, 4); + } else { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("[-] ERROR: UID size not defined"); + return false; + } + + // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID. + rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3]; + + rSAKc1[0] = sak; + AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2); + + rSAKc2[0] = sak & 0xFB; + AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2); + + // 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 + AddCrc14A(rRATS, sizeof(rRATS) - 2); + +#define TAG_RESPONSE_COUNT 8 + static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { + { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type + { .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid + { .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked + { .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1 + { .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2 + { .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS + { .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response + { .response = rSIGN, .response_n = sizeof(rSIGN) } // EV1/NTAG READ_SIG response + }; + + // "precompile" responses. There are 8 predefined responses with a total of 68 bytes data to transmit. + // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) + // 68 * 8 data bits, 68 * 1 parity bits, 8 start bits, 8 stop bits, 8 correction bits -- 636 bytes buffer +#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 636 + + uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); + // modulation buffer pointer and current buffer free space size + uint8_t *free_buffer_pointer = free_buffer; + size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; + + // 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 < TAG_RESPONSE_COUNT; i++) { + if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) { + BigBuf_free_keep_EM(); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Not enough modulation buffer size, exit after %d elements", i); + return false; + } + } + + *responses = responses_init; + + // indices into responses array: +#define ATQA 0 +#define UIDC1 1 +#define UIDC2 2 +#define SAKC1 3 +#define SAKC2 4 +#define RATS 5 +#define VERSION 6 +#define SIGNATURE 7 + + return true; } //----------------------------------------------------------------------------- @@ -824,708 +1028,651 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) { // response to send, and send it. // 'hf 14a sim' //----------------------------------------------------------------------------- -void SimulateIso14443aTag(int tagType, int flags, uint8_t* data) { +void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) { - #define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() +#define ATTACK_KEY_COUNT 8 // keep same as define in cmdhfmf.c -> readerAttack() - uint8_t sak = 0; - uint32_t cuid = 0; - uint32_t nonce = 0; - - // PACK response to PWD AUTH for EV1/NTAG - uint8_t response8[4] = {0,0,0,0}; - // Counter for EV1/NTAG - uint32_t counters[] = {0,0,0}; - - // The first response contains the ATQA (note: bytes are transmitted in reverse order). - uint8_t response1[] = {0,0}; + tag_response_info_t *responses; + uint32_t cuid = 0; + uint32_t nonce = 0; + uint32_t counters[3] = { 0x00, 0x00, 0x00 }; + uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd }; + uint8_t pages = 0; - // Here, we collect CUID, block1, keytype1, NT1, NR1, AR1, CUID, block2, keytyp2, NT2, NR2, AR2 - // it should also collect block, keytype. - uint8_t cardAUTHSC = 0; - uint8_t cardAUTHKEY = 0xff; // no authentication - // allow collecting up to 8 sets of nonces to allow recovery of up to 8 keys + // Here, we collect CUID, block1, keytype1, NT1, NR1, AR1, CUID, block2, keytyp2, NT2, NR2, AR2 + // it should also collect block, keytype. + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = 0xff; // no authentication + // allow collecting up to 8 sets of nonces to allow recovery of up to 8 keys - nonces_t ar_nr_nonces[ATTACK_KEY_COUNT]; // for attack types moebius - memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces)); - uint8_t moebius_count = 0; - - switch (tagType) { - case 1: { // MIFARE Classic 1k - response1[0] = 0x04; - sak = 0x08; - } break; - case 2: { // MIFARE Ultralight - response1[0] = 0x44; - sak = 0x00; - } break; - case 3: { // MIFARE DESFire - response1[0] = 0x04; - response1[1] = 0x03; - sak = 0x20; - } break; - case 4: { // ISO/IEC 14443-4 - javacard (JCOP) - response1[0] = 0x04; - sak = 0x28; - } break; - case 5: { // MIFARE TNP3XXX - response1[0] = 0x01; - response1[1] = 0x0f; - sak = 0x01; - } break; - case 6: { // MIFARE Mini 320b - response1[0] = 0x44; - sak = 0x09; - } break; - case 7: { // NTAG - response1[0] = 0x44; - sak = 0x00; - // PACK - response8[0] = 0x80; - response8[1] = 0x80; - compute_crc(CRC_14443_A, response8, 2, &response8[2], &response8[3]); - // uid not supplied then get from emulator memory - if (data[0]==0) { - uint16_t start = 4 * (0+12); - uint8_t emdata[8]; - emlGetMemBt( emdata, start, sizeof(emdata)); - memcpy(data, emdata, 3); // uid bytes 0-2 - memcpy(data+3, emdata+4, 4); // uid bytes 3-7 - flags |= FLAG_7B_UID_IN_DATA; - } - } break; - case 8: { // MIFARE Classic 4k - response1[0] = 0x02; - sak = 0x18; - } break; - case 9 : { // FM11RF005SH (Shanghai Metro) - response1[0] = 0x03; - response1[1] = 0x00; - sak = 0x0A; - } - 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}; + nonces_t ar_nr_nonces[ATTACK_KEY_COUNT]; // for attack types moebius + memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces)); + uint8_t moebius_count = 0; - // For UID size 7, - uint8_t response2a[5] = {0x00}; - - if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA ) { - response2[0] = 0x88; // Cascade Tag marker - response2[1] = data[0]; - response2[2] = data[1]; - response2[3] = data[2]; + // command buffers + uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 }; + uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 }; - response2a[0] = data[3]; - response2a[1] = data[4]; - response2a[2] = data[5]; - response2a[3] = data[6]; //?? - response2a[4] = response2a[0] ^ response2a[1] ^ response2a[2] ^ response2a[3]; + // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it + // Such a response is less time critical, so we can prepare them on the fly +#define DYNAMIC_RESPONSE_BUFFER_SIZE 64 +#define DYNAMIC_MODULATION_BUFFER_SIZE 512 + uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE]; + uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE]; + tag_response_info_t dynamic_response_info = { + .response = dynamic_response_buffer, + .response_n = 0, + .modulation = dynamic_modulation_buffer, + .modulation_n = 0 + }; - // Configure the ATQA and SAK accordingly - response1[0] |= 0x40; - sak |= 0x04; - - cuid = bytes_to_num(data+3, 4); - } else { - memcpy(response2, data, 4); - // Configure the ATQA and SAK accordingly - response1[0] &= 0xBF; - sak &= 0xFB; - cuid = bytes_to_num(data, 4); - } + // free eventually allocated BigBuf memory but keep Emulator Memory + BigBuf_free_keep_EM(); - // Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID. - response2[4] = response2[0] ^ response2[1] ^ response2[2] ^ response2[3]; + if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) { + BigBuf_free_keep_EM(); + reply_ng(CMD_SIMULATE_MIFARE_CARD, PM3_EINIT, NULL, 0); + return; + } - // Prepare the mandatory SAK (for 4 and 7 byte UID) - uint8_t response3[3] = {sak, 0x00, 0x00}; - compute_crc(CRC_14443_A, response3, 1, &response3[1], &response3[2]); + // We need to listen to the high-frequency, peak-detected path. + iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit - uint8_t response3a[3] = {0x00}; - response3a[0] = sak & 0xFB; - compute_crc(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); + int len = 0; - // Tag NONCE. - uint8_t response5[4]; - - 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 - compute_crc(CRC_14443_A, response6, 4, &response6[4], &response6[5]); - - // Prepare GET_VERSION (different for UL EV-1 / NTAG) - // uint8_t response7_EV1[] = {0x00, 0x04, 0x03, 0x01, 0x01, 0x00, 0x0b, 0x03, 0xfd, 0xf7}; //EV1 48bytes VERSION. - // uint8_t response7_NTAG[] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x11, 0x03, 0x01, 0x9e}; //NTAG 215 - // Prepare CHK_TEARING - // uint8_t response9[] = {0xBD,0x90,0x3f}; - - #define TAG_RESPONSE_COUNT 10 - tag_response_info_t responses[TAG_RESPONSE_COUNT] = { - { .response = response1, .response_n = sizeof(response1) }, // Answer to request - respond with card type - { .response = response2, .response_n = sizeof(response2) }, // Anticollision cascade1 - respond with uid - { .response = response2a, .response_n = sizeof(response2a) }, // Anticollision cascade2 - respond with 2nd half of uid if asked - { .response = response3, .response_n = sizeof(response3) }, // Acknowledge select - cascade 1 - { .response = response3a, .response_n = sizeof(response3a) }, // Acknowledge select - cascade 2 - { .response = response5, .response_n = sizeof(response5) }, // Authentication answer (random nonce) - { .response = response6, .response_n = sizeof(response6) }, // dummy ATS (pseudo-ATR), answer to RATS + // To control where we are in the protocol +#define ORDER_NONE 0 +#define ORDER_REQA 1 +#define ORDER_SELECT_ALL_CL1 2 +#define ORDER_SELECT_CL1 3 +#define ORDER_HALTED 5 +#define ORDER_WUPA 6 +#define ORDER_AUTH 7 +#define ORDER_SELECT_ALL_CL2 20 +#define ORDER_SELECT_CL2 30 +#define ORDER_EV1_COMP_WRITE 40 +#define ORDER_RATS 70 + int order = ORDER_NONE; - { .response = response8, .response_n = sizeof(response8) } // EV1/NTAG PACK response - }; - // { .response = response7_NTAG, .response_n = sizeof(response7_NTAG)}, // EV1/NTAG GET_VERSION response - // { .response = response9, .response_n = sizeof(response9) } // EV1/NTAG CHK_TEAR response - + int retval = PM3_SUCCESS; - // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it - // Such a response is less time critical, so we can prepare them on the fly - #define DYNAMIC_RESPONSE_BUFFER_SIZE 64 - #define DYNAMIC_MODULATION_BUFFER_SIZE 512 - uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE]; - uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE]; - tag_response_info_t dynamic_response_info = { - .response = dynamic_response_buffer, - .response_n = 0, - .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); + // Just to allow some checks + int happened = 0; + int happened2 = 0; + int cmdsRecvd = 0; - BigBuf_free_keep_EM(); - clear_trace(); - set_tracing(true); + // compatible write block number + uint8_t wrblock = 0; - // allocate buffers: - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); - free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); + clear_trace(); + set_tracing(true); + LED_A_ON(); + for (;;) { + WDT_HIT(); - // 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 2) { - // send NACK 0x0 == invalid argument - uint8_t nack[] = {0x00}; - EmSendCmd(nack,sizeof(nack)); - } else { - uint8_t cmd[] = {0x00,0x00,0x00,0x14,0xa5}; - num_to_bytes(counters[index], 3, cmd); - AddCrc14A(cmd, sizeof(cmd)-2); - EmSendCmd(cmd,sizeof(cmd)); - } - p_response = NULL; - } else if (receivedCmd[0] == MIFARE_ULEV1_INCR_CNT && tagType == 7) { // Received a INC COUNTER -- - uint8_t index = receivedCmd[1]; - if ( index > 2) { - // send NACK 0x0 == invalid argument - uint8_t nack[] = {0x00}; - EmSendCmd(nack,sizeof(nack)); - } else { + } else if (order == ORDER_AUTH && len == 8) { + // Received {nr] and {ar} (part of authentication) + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + uint32_t nr = bytes_to_num(receivedCmd, 4); + uint32_t ar = bytes_to_num(receivedCmd + 4, 4); - uint32_t val = bytes_to_num(receivedCmd+2,4); - - // if new value + old value is bigger 24bits, fail - if ( val + counters[index] > 0xFFFFFF ) { - // send NACK 0x4 == counter overflow - uint8_t nack[] = {0x04}; - EmSendCmd(nack,sizeof(nack)); - } else { - counters[index] = val; - // send ACK - uint8_t ack[] = {0x0a}; - EmSendCmd(ack,sizeof(ack)); - } - } - p_response = NULL; - } else if (receivedCmd[0] == MIFARE_ULEV1_CHECKTEAR && tagType == 7) { // Received a CHECK_TEARING_EVENT -- - // first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature] - uint8_t emdata[3]; - uint8_t index = receivedCmd[1]; - if ( index > 2) { - // send NACK 0x0 == invalid argument - uint8_t nack[] = {0x00}; - EmSendCmd(nack,sizeof(nack)); - } else { - emlGetMemBt( emdata, 10+index, 1); - AddCrc14A(emdata, sizeof(emdata)-2); - EmSendCmd(emdata, sizeof(emdata)); - } - p_response = NULL; - } else if (receivedCmd[0] == ISO14443A_CMD_HALT) { // Received a HALT - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - p_response = NULL; - } else if (receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) { // Received an authentication request - if ( tagType == 7 ) { // IF NTAG /EV1 0x60 == GET_VERSION, not a authentication request. - uint8_t emdata[10]; - emlGetMemBt( emdata, 0, 8 ); - AddCrc14A(emdata, sizeof(emdata)-2); - EmSendCmd(emdata, sizeof(emdata)); - p_response = NULL; - } else { - - cardAUTHKEY = receivedCmd[0] - 0x60; - cardAUTHSC = receivedCmd[1] / 4; // received block num - - // incease nonce at AUTH requests. this is time consuming. - nonce = prng_successor( GetTickCount(), 32 ); - //num_to_bytes(nonce, 4, response5); - num_to_bytes(nonce, 4, dynamic_response_info.response); - dynamic_response_info.response_n = 4; + // Collect AR/NR per keytype & sector + if ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { - //prepare_tag_modulation(&responses[5], DYNAMIC_MODULATION_BUFFER_SIZE); - prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE); - p_response = &dynamic_response_info; - //p_response = &responses[5]; - order = 7; - } - } else if (receivedCmd[0] == ISO14443A_CMD_RATS) { // Received a RATS request - if (tagType == 1 || tagType == 2) { // RATS not supported - EmSend4bit(CARD_NACK_NA); - p_response = NULL; - } else { - p_response = &responses[6]; order = 70; - } - } else if (order == 7 && len == 8) { // Received {nr] and {ar} (part of authentication) - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - 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) == FLAG_NR_AR_ATTACK ) { - - int8_t index = -1; - int8_t empty = -1; - for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - // find which index to use - if ( (cardAUTHSC == ar_nr_nonces[i].sector) && (cardAUTHKEY == ar_nr_nonces[i].keytype)) - index = i; + int8_t index = -1; + int8_t empty = -1; + for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + // find which index to use + if ((cardAUTHSC == ar_nr_nonces[i].sector) && (cardAUTHKEY == ar_nr_nonces[i].keytype)) + index = i; - // keep track of empty slots. - if ( ar_nr_nonces[i].state == EMPTY) - empty = i; - } - // if no empty slots. Choose first and overwrite. - if ( index == -1 ) { - if ( empty == -1 ) { - index = 0; - ar_nr_nonces[index].state = EMPTY; - } else { - index = empty; - } - } + // keep track of empty slots. + if (ar_nr_nonces[i].state == EMPTY) + empty = i; + } + // if no empty slots. Choose first and overwrite. + if (index == -1) { + if (empty == -1) { + index = 0; + ar_nr_nonces[index].state = EMPTY; + } else { + index = empty; + } + } - switch(ar_nr_nonces[index].state) { - case EMPTY: { - // first nonce collect - ar_nr_nonces[index].cuid = cuid; - ar_nr_nonces[index].sector = cardAUTHSC; - ar_nr_nonces[index].keytype = cardAUTHKEY; - ar_nr_nonces[index].nonce = nonce; - ar_nr_nonces[index].nr = nr; - ar_nr_nonces[index].ar = ar; - ar_nr_nonces[index].state = FIRST; - break; - } - case FIRST : { - // second nonce collect - ar_nr_nonces[index].nonce2 = nonce; - ar_nr_nonces[index].nr2 = nr; - ar_nr_nonces[index].ar2 = ar; - ar_nr_nonces[index].state = SECOND; + switch (ar_nr_nonces[index].state) { + case EMPTY: { + // first nonce collect + ar_nr_nonces[index].cuid = cuid; + ar_nr_nonces[index].sector = cardAUTHSC; + ar_nr_nonces[index].keytype = cardAUTHKEY; + ar_nr_nonces[index].nonce = nonce; + ar_nr_nonces[index].nr = nr; + ar_nr_nonces[index].ar = ar; + ar_nr_nonces[index].state = FIRST; + break; + } + case FIRST : { + // second nonce collect + ar_nr_nonces[index].nonce2 = nonce; + ar_nr_nonces[index].nr2 = nr; + ar_nr_nonces[index].ar2 = ar; + ar_nr_nonces[index].state = SECOND; - // send to client - cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, 0, 0, &ar_nr_nonces[index], sizeof(nonces_t)); - - ar_nr_nonces[index].state = EMPTY; - ar_nr_nonces[index].sector = 0; - ar_nr_nonces[index].keytype = 0; - - moebius_count++; - break; - } - default: break; - } - } - p_response = NULL; - - } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1 ) { // ULC authentication, or Desfire Authentication - } else if (receivedCmd[0] == MIFARE_ULEV1_AUTH) { // NTAG / EV-1 authentication - if ( tagType == 7 ) { - uint16_t start = 13; // first 4 blocks of emu are [getversion answer - check tearing - pack - 0x00] - uint8_t emdata[4]; - emlGetMemBt( emdata, start, 2); - AddCrc14A(emdata, 2); - EmSendCmd(emdata, sizeof(emdata)); - p_response = NULL; - uint32_t pwd = bytes_to_num(receivedCmd+1,4); - - if ( MF_DBGLEVEL >= 3) Dbprintf("Auth attempt: %08x", pwd); - } - } else { - // Check for ISO 14443A-4 compliant commands, look at left nibble - switch (receivedCmd[0]) { - case 0x02: - case 0x03: { // IBlock (command no CID) - dynamic_response_info.response[0] = receivedCmd[0]; - dynamic_response_info.response[1] = 0x90; - dynamic_response_info.response[2] = 0x00; - dynamic_response_info.response_n = 3; - } break; - case 0x0B: - case 0x0A: { // IBlock (command CID) - dynamic_response_info.response[0] = receivedCmd[0]; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response[2] = 0x90; - dynamic_response_info.response[3] = 0x00; - dynamic_response_info.response_n = 4; - } break; + // send to client (one struct nonces_t) + reply_ng(CMD_SIMULATE_MIFARE_CARD, PM3_SUCCESS, (uint8_t *)&ar_nr_nonces[index], sizeof(nonces_t)); - case 0x1A: - case 0x1B: { // Chaining command - dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1); - dynamic_response_info.response_n = 2; - } break; + ar_nr_nonces[index].state = EMPTY; + ar_nr_nonces[index].sector = 0; + ar_nr_nonces[index].keytype = 0; - case 0xAA: - case 0xBB: { - dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; - dynamic_response_info.response_n = 2; - } break; - - case 0xBA: { // ping / pong - dynamic_response_info.response[0] = 0xAB; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response_n = 2; - } break; + moebius_count++; + break; + } + default: + break; + } + } + order = ORDER_NONE; // back to work state + p_response = NULL; - case 0xCA: - case 0xC2: { // Readers sends deselect command - dynamic_response_info.response[0] = 0xCA; - dynamic_response_info.response[1] = 0x00; - dynamic_response_info.response_n = 2; - } break; + // + // now check commands in received buffer + // - default: { - // Never seen this command before - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - Dbprintf("Received unknown command (len=%d):",len); - Dbhexdump(len,receivedCmd,false); - // Do not respond - dynamic_response_info.response_n = 0; - } break; - } - - if (dynamic_response_info.response_n > 0) { - // Copy the CID from the reader query - dynamic_response_info.response[1] = receivedCmd[1]; + } else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST + p_response = &responses[ATQA]; + order = ORDER_REQA; + } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP + p_response = &responses[ATQA]; + order = ORDER_WUPA; + } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) + p_response = &responses[UIDC1]; + order = ORDER_SELECT_ALL_CL1; + } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2) + p_response = &responses[UIDC2]; + order = ORDER_SELECT_ALL_CL2; + } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) + p_response = &responses[SAKC1]; + order = ORDER_SELECT_CL1; + } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2) + p_response = &responses[SAKC2]; + order = ORDER_SELECT_CL2; + } else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ + uint8_t block = receivedCmd[1]; + // if Ultralight or NTAG (4 byte blocks) + if (tagType == 7 || tagType == 2) { + if (block > pages) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + // first blocks of emu are header + uint16_t start = block * 4 + MFU_DUMP_PREFIX_LENGTH; + uint8_t emdata[MAX_MIFARE_FRAME_SIZE]; + emlGetMemBt(emdata, start, 16); + AddCrc14A(emdata, 16); + EmSendCmd(emdata, sizeof(emdata)); + } + // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below + p_response = NULL; + } else if (tagType == 9 && block == 1) { + // FM11005SH. 16blocks, 4bytes / block. + // block0 = 2byte Customer ID (CID), 2byte Manufacture ID (MID) + // block1 = 4byte UID. + p_response = &responses[UIDC1]; + } else { // all other tags (16 byte block tags) + uint8_t emdata[MAX_MIFARE_FRAME_SIZE]; + emlGetMemBt(emdata, block, 16); + AddCrc14A(emdata, 16); + EmSendCmd(emdata, sizeof(emdata)); + // EmSendCmd(data+(4*receivedCmd[1]),16); + // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); + // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below + p_response = NULL; + } + } else if (receivedCmd[0] == MIFARE_ULEV1_FASTREAD && len == 5) { // Received a FAST READ (ranged read) + uint8_t block1 = receivedCmd[1]; + uint8_t block2 = receivedCmd[2]; + if (block1 > pages) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + uint8_t emdata[MAX_FRAME_SIZE]; + // first blocks of emu are header + int start = block1 * 4 + MFU_DUMP_PREFIX_LENGTH; + len = (block2 - block1 + 1) * 4; + emlGetMemBt(emdata, start, len); + AddCrc14A(emdata, len); + EmSendCmd(emdata, len + 2); + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE + // cmd + block + 4 bytes data + 2 bytes crc + bool isCrcCorrect = CheckCrc14A(receivedCmd, len); + if (isCrcCorrect) { + uint8_t block = receivedCmd[1]; + if (block > pages) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + // first blocks of emu are header + emlSetMem_xt(&receivedCmd[2], block + MFU_DUMP_PREFIX_LENGTH / 4, 1, 4); + // send ACK + EmSend4bit(CARD_ACK); + } + } else { + // send NACK 0x1 == crc/parity error + EmSend4bit(CARD_NACK_PA); + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7)) { + // cmd + block + 2 bytes crc + bool isCrcCorrect = CheckCrc14A(receivedCmd, len); + if (isCrcCorrect) { + wrblock = receivedCmd[1]; + if (wrblock > pages) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + // send ACK + EmSend4bit(CARD_ACK); + // go to part 2 + order = ORDER_EV1_COMP_WRITE; + } + } else { + // send NACK 0x1 == crc/parity error + EmSend4bit(CARD_NACK_PA); + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULEV1_READSIG && len == 4 && tagType == 7) { // Received a READ SIGNATURE -- + p_response = &responses[SIGNATURE]; + } else if (receivedCmd[0] == MIFARE_ULEV1_READ_CNT && len == 4 && tagType == 7) { // Received a READ COUNTER -- + uint8_t index = receivedCmd[1]; + if (index > 2) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + uint8_t cmd[] = {0x00, 0x00, 0x00, 0x14, 0xa5}; + htole24(counters[index], cmd); + AddCrc14A(cmd, sizeof(cmd) - 2); + EmSendCmd(cmd, sizeof(cmd)); + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULEV1_INCR_CNT && len == 8 && tagType == 7) { // Received a INC COUNTER -- + uint8_t index = receivedCmd[1]; + if (index > 2) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + uint32_t val = le24toh(receivedCmd + 2) + counters[index]; + // if new value + old value is bigger 24bits, fail + if (val > 0xFFFFFF) { + // send NACK 0x4 == counter overflow + EmSend4bit(CARD_NACK_NA); + } else { + counters[index] = val; + // send ACK + EmSend4bit(CARD_ACK); + } + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULEV1_CHECKTEAR && len == 4 && tagType == 7) { // Received a CHECK_TEARING_EVENT -- + // first 12 blocks of emu are [getversion answer - check tearing - pack - 0x00 - signature] + uint8_t index = receivedCmd[1]; + if (index > 2) { + // send NACK 0x0 == invalid argument + EmSend4bit(CARD_NACK_IV); + } else { + uint8_t cmd[3]; + cmd[0] = tearings[index]; + AddCrc14A(cmd, sizeof(cmd) - 2); + EmSendCmd(cmd, sizeof(cmd)); + } + p_response = NULL; + } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + p_response = NULL; + order = ORDER_HALTED; + } else if (receivedCmd[0] == MIFARE_ULEV1_VERSION && len == 3 && (tagType == 2 || tagType == 7)) { + p_response = &responses[VERSION]; + } else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request + cardAUTHKEY = receivedCmd[0] - 0x60; + cardAUTHSC = receivedCmd[1] / 4; // received block num - // Add CRC bytes, always used in ISO 14443A-4 compliant cards - AddCrc14A(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) { - DbpString("Error preparing tag response"); - LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - p_response = &dynamic_response_info; - } - } + // incease nonce at AUTH requests. this is time consuming. + nonce = prng_successor(GetTickCount(), 32); + num_to_bytes(nonce, 4, dynamic_response_info.response); + dynamic_response_info.response_n = 4; - // Count number of wakeups received after a halt - if (order == 6 && lastorder == 5) { happened++; } + prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE); + p_response = &dynamic_response_info; + order = ORDER_AUTH; + } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request + if (tagType == 1 || tagType == 2) { // RATS not supported + EmSend4bit(CARD_NACK_NA); + p_response = NULL; + } else { + p_response = &responses[RATS]; + order = ORDER_RATS; + } + } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULEV1_AUTH && len == 7 && tagType == 7) { // NTAG / EV-1 authentication + // PWD stored in dump now + uint8_t pwd[4]; + emlGetMemBt(pwd, (pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd)); + if (memcmp(receivedCmd + 1, pwd, 4) == 0) { + uint8_t cmd[4]; + emlGetMemBt(cmd, pages * 4 + MFU_DUMP_PREFIX_LENGTH, 2); + AddCrc14A(cmd, sizeof(cmd) - 2); + EmSendCmd(cmd, sizeof(cmd)); + } else { + EmSend4bit(CARD_NACK_NA); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Auth attempt: %08x", bytes_to_num(receivedCmd + 1, 4)); + } + p_response = NULL; + } else if (receivedCmd[0] == MIFARE_ULEV1_VCSL && len == 23 && tagType == 7) { + uint8_t cmd[3]; + emlGetMemBt(cmd, (pages - 2) * 4 + 1 + MFU_DUMP_PREFIX_LENGTH, 1); + AddCrc14A(cmd, sizeof(cmd) - 2); + EmSendCmd(cmd, sizeof(cmd)); + p_response = NULL; + } else { + // Check for ISO 14443A-4 compliant commands, look at left nibble + switch (receivedCmd[0]) { + case 0x02: + case 0x03: { // IBlock (command no CID) + dynamic_response_info.response[0] = receivedCmd[0]; + dynamic_response_info.response[1] = 0x90; + dynamic_response_info.response[2] = 0x00; + dynamic_response_info.response_n = 3; + } + break; + case 0x0B: + case 0x0A: { // IBlock (command CID) + dynamic_response_info.response[0] = receivedCmd[0]; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response[2] = 0x90; + dynamic_response_info.response[3] = 0x00; + dynamic_response_info.response_n = 4; + } + break; - // Count number of other messages after a halt - if (order != 6 && lastorder == 5) { happened2++; } + case 0x1A: + case 0x1B: { // Chaining command + dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1); + dynamic_response_info.response_n = 2; + } + break; - cmdsRecvd++; + case 0xAA: + case 0xBB: { + dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; + dynamic_response_info.response_n = 2; + } + break; - if (p_response != NULL) { - EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n); - // do the tracing for the previous reader request and this tag answer: - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(p_response->response, p_response->response_n, par); - - EmLogTrace(Uart.output, - Uart.len, - Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parity, - p_response->response, - p_response->response_n, - LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, - (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - par); - } - } + case 0xBA: { // ping / pong + dynamic_response_info.response[0] = 0xAB; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response_n = 2; + } + break; - cmd_send(CMD_ACK,1,0,0,0,0); - switch_off(); - - BigBuf_free_keep_EM(); - - if (MF_DBGLEVEL >= 4){ - Dbprintf("-[ Wake ups after halt [%d]", happened); - Dbprintf("-[ Messages after halt [%d]", happened2); - Dbprintf("-[ Num of received cmd [%d]", cmdsRecvd); - Dbprintf("-[ Num of moebius tries [%d]", moebius_count); - } + case 0xCA: + case 0xC2: { // Readers sends deselect command + dynamic_response_info.response[0] = 0xCA; + dynamic_response_info.response[1] = 0x00; + dynamic_response_info.response_n = 2; + } + break; + + default: { + // Never seen this command before + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + if (DBGLEVEL >= DBG_DEBUG) { + Dbprintf("Received unknown command (len=%d):", len); + Dbhexdump(len, receivedCmd, false); + } + // Do not respond + dynamic_response_info.response_n = 0; + order = ORDER_NONE; // back to work state + } + break; + } + + if (dynamic_response_info.response_n > 0) { + // Copy the CID from the reader query + dynamic_response_info.response[1] = receivedCmd[1]; + + // Add CRC bytes, always used in ISO 14443A-4 compliant cards + AddCrc14A(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) { + if (DBGLEVEL >= DBG_DEBUG) DbpString("Error preparing tag response"); + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + break; + } + p_response = &dynamic_response_info; + } + } + + // Count number of wakeups received after a halt + if (order == ORDER_WUPA && lastorder == ORDER_HALTED) { happened++; } + + // Count number of other messages after a halt + if (order != ORDER_WUPA && lastorder == ORDER_HALTED) { happened2++; } + + cmdsRecvd++; + + if (p_response != NULL) { + EmSendPrecompiledCmd(p_response); + } + } + + switch_off(); + + set_tracing(false); + BigBuf_free_keep_EM(); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("-[ Wake ups after halt [%d]", happened); + Dbprintf("-[ Messages after halt [%d]", happened2); + Dbprintf("-[ Num of received cmd [%d]", cmdsRecvd); + Dbprintf("-[ Num of moebius tries [%d]", moebius_count); + } + + reply_ng(CMD_SIMULATE_MIFARE_CARD, retval, NULL, 0); } // prepare a delayed transfer. This simply shifts ToSend[] by a number // of bits specified in the delay parameter. void PrepareDelayedTransfer(uint16_t delay) { - delay &= 0x07; - if (!delay) return; + delay &= 0x07; + if (!delay) return; - uint8_t bitmask = 0; - uint8_t bits_to_shift = 0; - uint8_t bits_shifted = 0; - uint16_t i = 0; + uint8_t bitmask = 0; + uint8_t bits_shifted = 0; - for (i = 0; i < delay; i++) - bitmask |= (0x01 << i); + for (uint16_t i = 0; i < delay; i++) + bitmask |= (0x01 << i); - ToSend[ToSendMax++] = 0x00; + ToSend[ToSendMax++] = 0x00; - for (i = 0; i < ToSendMax; i++) { - bits_to_shift = ToSend[i] & bitmask; - ToSend[i] = ToSend[i] >> delay; - ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay)); - bits_shifted = bits_to_shift; - } - } + for (uint16_t i = 0; i < ToSendMax; i++) { + uint8_t bits_to_shift = ToSend[i] & bitmask; + ToSend[i] = ToSend[i] >> delay; + ToSend[i] = ToSend[i] | (bits_shifted << (8 - delay)); + bits_shifted = bits_to_shift; + } +} //------------------------------------------------------------------------------------- // 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 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) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - if (timing) { - if (*timing == 0) // Measure time - *timing = (GetCountSspClk() + 8) & 0xfffffff8; - else - 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) - LastTimeProxToAirStart = *timing; - } else { - - uint32_t ThisTransferTime = 0; - ThisTransferTime = ((MAX(NextTransferTime, GetCountSspClk()) & 0xfffffff8) + 8); + if (timing) { + if (*timing == 0) // Measure time + *timing = (GetCountSspClk() + 8) & 0xfffffff8; + else + PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) - while (GetCountSspClk() < ThisTransferTime) {}; + if (DBGLEVEL >= DBG_EXTENDED && GetCountSspClk() >= (*timing & 0xfffffff8)) + Dbprintf("TransmitFor14443a: Missed timing"); + while (GetCountSspClk() < (*timing & 0xfffffff8)) {}; // Delay transfer (multiple of 8 MF clock ticks) + LastTimeProxToAirStart = *timing; + } else { - LastTimeProxToAirStart = ThisTransferTime; - } - - // clear TXRDY - AT91C_BASE_SSC->SSC_THR = SEC_Y; + uint32_t ThisTransferTime = 0; + ThisTransferTime = ((MAX(NextTransferTime, GetCountSspClk()) & 0xfffffff8) + 8); - volatile uint8_t b; - uint16_t c = 0; - while (c < len) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c++]; - } - //iceman test - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b; - } - } - - NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); + while (GetCountSspClk() < ThisTransferTime) {}; + + LastTimeProxToAirStart = ThisTransferTime; + } + + // clear TXRDY + AT91C_BASE_SSC->SSC_THR = SEC_Y; + + volatile uint8_t b; + uint16_t c = 0; + while (c < len) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c++]; + } + //iceman test + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); + (void)b; + } + } + + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); } //----------------------------------------------------------------------------- // Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *parity) { - int i, j; - int last = 0; - uint8_t b; +void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *par) { + int last = 0; - ToSendReset(); + ToSendReset(); - // Start of Communication (Seq. Z) - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax+1) - 6; + // Start of Communication (Seq. Z) + ToSend[++ToSendMax] = SEC_Z; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; - size_t bytecount = nbytes(bits); - // Generate send structure for the data bits - for (i = 0; i < bytecount; i++) { - // Get the current byte to send - b = cmd[i]; - size_t bitsleft = MIN((bits-(i*8)),8); + size_t bytecount = nbytes(bits); + // Generate send structure for the data bits + for (int i = 0; i < bytecount; i++) { + // Get the current byte to send + uint8_t b = cmd[i]; + size_t bitsleft = MIN((bits - (i * 8)), 8); + int j; + for (j = 0; j < bitsleft; j++) { + if (b & 1) { + // Sequence X + ToSend[++ToSendMax] = SEC_X; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 2; + last = 1; + } else { + if (last == 0) { + // Sequence Z + ToSend[++ToSendMax] = SEC_Z; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + } else { + // Sequence Y + ToSend[++ToSendMax] = SEC_Y; + last = 0; + } + } + b >>= 1; + } - for (j = 0; j < bitsleft; j++) { - if (b & 1) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - LastProxToAirDuration = 8 * (ToSendMax+1) - 2; - last = 1; - } else { - if (last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax+1) - 6; - } else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - } - b >>= 1; - } + // Only transmit parity bit if we transmitted a complete byte + if (j == 8 && par != NULL) { + // Get the parity bit + if (par[i >> 3] & (0x80 >> (i & 0x0007))) { + // Sequence X + ToSend[++ToSendMax] = SEC_X; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 2; + last = 1; + } else { + if (last == 0) { + // Sequence Z + ToSend[++ToSendMax] = SEC_Z; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + } else { + // Sequence Y + ToSend[++ToSendMax] = SEC_Y; + last = 0; + } + } + } + } - // Only transmit parity bit if we transmitted a complete byte - if (j == 8 && parity != NULL) { - // Get the parity bit - if (parity[i>>3] & (0x80 >> (i&0x0007))) { - // Sequence X - ToSend[++ToSendMax] = SEC_X; - LastProxToAirDuration = 8 * (ToSendMax+1) - 2; - last = 1; - } else { - if (last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax+1) - 6; - } else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - } - } - } + // End of Communication: Logic 0 followed by Sequence Y + if (last == 0) { + // Sequence Z + ToSend[++ToSendMax] = SEC_Z; + LastProxToAirDuration = 8 * (ToSendMax + 1) - 6; + } else { + // Sequence Y + ToSend[++ToSendMax] = SEC_Y; + } + ToSend[++ToSendMax] = SEC_Y; - // End of Communication: Logic 0 followed by Sequence Y - if (last == 0) { - // Sequence Z - ToSend[++ToSendMax] = SEC_Z; - LastProxToAirDuration = 8 * (ToSendMax+1) - 6; - } else { - // Sequence Y - ToSend[++ToSendMax] = SEC_Y; - last = 0; - } - ToSend[++ToSendMax] = SEC_Y; - - // Convert to length of command: - ToSendMax++; + // Convert to length of command: + ToSendMax++; } //----------------------------------------------------------------------------- // Prepare reader command to send to FPGA //----------------------------------------------------------------------------- -void CodeIso14443aAsReaderPar(const uint8_t *cmd, uint16_t len, const uint8_t *parity) { - CodeIso14443aBitsAsReaderPar(cmd, len*8, parity); +void CodeIso14443aAsReaderPar(const uint8_t *cmd, uint16_t len, const uint8_t *par) { + CodeIso14443aBitsAsReaderPar(cmd, len * 8, par); } //----------------------------------------------------------------------------- @@ -1533,193 +1680,238 @@ void CodeIso14443aAsReaderPar(const uint8_t *cmd, uint16_t len, const uint8_t *p // 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) { - *len = 0; +int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { + *len = 0; - uint32_t timer = 0, vtime = 0; - int analogCnt = 0; - int analogAVG = 0; + uint32_t timer = 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); + // 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); - // 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); - // start ADC - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - - // Now run a 'software UART' on the stream of incoming samples. - UartInit(received, parity); + // 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); + // start ADC + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - // Clear RXRDY: + // Now run a 'software UART' on the stream of incoming samples. + UartInit(received, par); + + // Clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - for(;;) { - WDT_HIT(); + (void)b; - if (BUTTON_PRESS()) return 1; + uint16_t check = 0; - // 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 ((MAX_ADC_HF_VOLTAGE * (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; - } - } + for (;;) { + WDT_HIT(); - // 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; - } + if (check == 1000) { + if (BUTTON_PRESS() || data_available()) + return 1; + check = 0; } - } + ++check; + + // 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 ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { + if (timer == 0) { + timer = GetTickCount(); + } else { + // 50ms no field --> card to idle state + if (GetTickCountDelta(timer) > 50) { + return 2; + } + } + } else { + timer = 0; + } + analogCnt = 0; + analogAVG = 0; + } + } + + // 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; + } + } + } } int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { - volatile uint8_t b; - uint16_t i = 0; - uint32_t ThisTransferTime; - bool correctionNeeded; - - // Modulate Manchester - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); + volatile uint8_t b; + uint16_t i = 0; + uint32_t ThisTransferTime; + bool correctionNeeded; - // 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; - } - else - { - // The parity bits are left-aligned - correctionNeeded = Uart.parity[(Uart.len-1)/8] & (0x80 >> ((Uart.len-1) & 7)); - } - // 1236, so correction bit needed - i = (correctionNeeded) ? 0 : 1; + // Modulate Manchester + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); - // 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)); - 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 (uint8_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; - } + // 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; + } else { + // The parity bits are left-aligned + correctionNeeded = Uart.parity[(Uart.len - 1) / 8] & (0x80 >> ((Uart.len - 1) & 7)); + } + // 1236, so correction bit needed + i = (correctionNeeded) ? 0 : 1; - while ((ThisTransferTime = GetCountSspClk()) & 0x00000007); + // 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)); + b = AT91C_BASE_SSC->SSC_RHR; + (void) b; - // Clear TXRDY: - AT91C_BASE_SSC->SSC_THR = SEC_F; + // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) + for (uint8_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; + } - // send cycle - 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 (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b; - } - if(BUTTON_PRESS()) break; - } + while ((ThisTransferTime = GetCountSspClk()) & 0x00000007); - // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: - uint8_t fpga_queued_bits = FpgaSendQueueDelay >> 3; - for (i = 0; i <= fpga_queued_bits/8 + 1; ) { - 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; + // Clear TXRDY: + AT91C_BASE_SSC->SSC_THR = SEC_F; + + // send cycle + 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 (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); + (void)b; + } + if (BUTTON_PRESS()) break; + } + + // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: + uint8_t fpga_queued_bits = FpgaSendQueueDelay >> 3; + for (i = 0; i <= fpga_queued_bits / 8 + 1;) { + 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 EmSend4bit(uint8_t resp){ - Code4bitAnswerAsTag(resp); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // do the tracing for the previous reader request and this tag answer: - uint8_t par[1] = {0x00}; - GetParity(&resp, 1, par); - EmLogTrace(Uart.output, - Uart.len, - Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parity, - &resp, - 1, - LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, - (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - par); - return res; +int EmSend4bit(uint8_t resp) { + Code4bitAnswerAsTag(resp); + int res = EmSendCmd14443aRaw(ToSend, ToSendMax); + // do the tracing for the previous reader request and this tag answer: + uint8_t par[1] = {0x00}; + GetParity(&resp, 1, par); + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, + Uart.parity, + &resp, + 1, + LastTimeProxToAirStart * 16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + LastProxToAirDuration) * 16 + DELAY_ARM2AIR_AS_TAG, + par); + return res; +} +int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) { + return EmSendCmdParEx(resp, respLen, par, false); +} +int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision) { + CodeIso14443aAsTagPar(resp, respLen, par, collision); + int res = EmSendCmd14443aRaw(ToSend, ToSendMax); + // 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.parity, + resp, + respLen, + LastTimeProxToAirStart * 16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + LastProxToAirDuration) * 16 + DELAY_ARM2AIR_AS_TAG, + par); + return res; +} +int EmSendCmd(uint8_t *resp, uint16_t respLen) { + return EmSendCmdEx(resp, respLen, false); +} +int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision) { + uint8_t par[MAX_PARITY_SIZE] = {0x00}; + GetParity(resp, respLen, par); + return EmSendCmdParEx(resp, respLen, par, collision); } -int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ - CodeIso14443aAsTagPar(resp, respLen, par); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // 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.parity, - resp, - respLen, - LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, - (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - par); - return res; +int EmSendPrecompiledCmd(tag_response_info_t *p_response) { + int ret = EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n); + // do the tracing for the previous reader request and this tag answer: + uint8_t par[MAX_PARITY_SIZE] = {0x00}; + GetParity(p_response->response, p_response->response_n, par); + + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, + Uart.parity, + p_response->response, + p_response->response_n, + LastTimeProxToAirStart * 16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + p_response->ProxToAirDuration) * 16 + DELAY_ARM2AIR_AS_TAG, + par); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("response_info->response %02X", p_response->response); + Dbprintf("response_info->response_n %02X", p_response->response_n); + Dbprintf("response_info->par %02X", &(p_response->par)); + } + + return ret; } -int EmSendCmd(uint8_t *resp, uint16_t respLen){ - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(resp, respLen, par); - return EmSendCmdPar(resp, respLen, par); -} +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, + uint32_t reader_EndTime, uint8_t *reader_Parity, uint8_t *tag_data, + uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) { -bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, - uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) -{ - // 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_EndTime, reader_Parity, true)) - return false; - else - return(!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, false)); + // 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_EndTime, reader_Parity, true)) + return false; + else + return (!LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, false)); } @@ -1729,463 +1921,439 @@ bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_Start // If it takes too long return FALSE //----------------------------------------------------------------------------- static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { - uint32_t c = 0; - - // 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); + uint32_t c = 0; - // clear RXRDY: + // 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); + + // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; - uint32_t timeout = iso14a_get_timeout(); - for(;;) { - WDT_HIT(); + uint32_t timeout = iso14a_get_timeout(); + for (;;) { + WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - 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++ > timeout && Demod.state == DEMOD_UNSYNCD) { - return false; - } - } - } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + 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++ > timeout && Demod.state == DEMOD_UNSYNCD) { + return false; + } + } + } } -void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { +void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { - CodeIso14443aBitsAsReaderPar(frame, bits, par); - // Send command to tag - TransmitFor14443a(ToSend, ToSendMax, timing); - if(trigger) LED_A_ON(); - - LogTrace(frame, nbytes(bits), (LastTimeProxToAirStart<<4) + DELAY_ARM2AIR_AS_READER, ((LastTimeProxToAirStart + LastProxToAirDuration)<<4) + DELAY_ARM2AIR_AS_READER, par, true); + CodeIso14443aBitsAsReaderPar(frame, bits, par); + // Send command to tag + TransmitFor14443a(ToSend, ToSendMax, timing); + if (trigger) LED_A_ON(); + + LogTrace(frame, nbytes(bits), (LastTimeProxToAirStart << 4) + DELAY_ARM2AIR_AS_READER, ((LastTimeProxToAirStart + LastProxToAirDuration) << 4) + DELAY_ARM2AIR_AS_READER, par, 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, uint16_t len, uint8_t *par, uint32_t *timing) { + ReaderTransmitBitsPar(frame, len * 8, par, timing); } -void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(frame, len/8, par); - ReaderTransmitBitsPar(frame, len, par, timing); +void ReaderTransmitBits(uint8_t *frame, uint16_t len, uint32_t *timing) { + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE] = {0x00}; + GetParity(frame, len / 8, par); + ReaderTransmitBitsPar(frame, len, par, timing); } -void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) { - // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(frame, len, par); - ReaderTransmitBitsPar(frame, len*8, par, timing); +void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing) { + // Generate parity and redirect + uint8_t par[MAX_PARITY_SIZE] = {0x00}; + GetParity(frame, len, par); + ReaderTransmitBitsPar(frame, len * 8, par, timing); } -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); - return Demod.len; +int ReaderReceiveOffset(uint8_t *receivedAnswer, uint16_t offset, uint8_t *par) { + if (!GetIso14443aAnswerFromTag(receivedAnswer, par, offset)) + return false; + LogTrace(receivedAnswer, Demod.len, Demod.startTime * 16 - DELAY_AIR2ARM_AS_READER, Demod.endTime * 16 - DELAY_AIR2ARM_AS_READER, par, false); + return Demod.len; } -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); - return Demod.len; +int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par) { + if (!GetIso14443aAnswerFromTag(receivedAnswer, par, 0)) + return false; + LogTrace(receivedAnswer, Demod.len, Demod.startTime * 16 - DELAY_AIR2ARM_AS_READER, Demod.endTime * 16 - DELAY_AIR2ARM_AS_READER, par, false); + return Demod.len; } // This function misstreats the ISO 14443a anticollision procedure. -// by fooling the reader there is a collision and forceing the reader to +// by fooling the reader there is a collision and forceing the reader to // increase the uid bytes. The might be an overflow, DoS will occure. -void iso14443a_antifuzz(uint32_t flags){ - /* - uint8_t uidlen = 4+1+1+2; - if (( flags & 2 ) == 2 ) - uidlen = 7+1+1+2; - if (( flags & 4 ) == 4 ) - uidlen = 10+1+1+2; - - uint8_t *uid = BigBuf_malloc(uidlen); - - // The first response contains the ATQA (note: bytes are transmitted in reverse order). - // Mifare Classic 1K - uint8_t atqa[] = {0x04, 0}; +void iso14443a_antifuzz(uint32_t flags) { - if ( (flags & 2) == 2 ) { - uid[0] = 0x88; // Cascade Tag marker - uid[1] = 0x01; + // We need to listen to the high-frequency, peak-detected path. + iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Configure the ATQA accordingly - atqa[0] |= 0x40; - } else { - memcpy(response2, data, 4); - // Configure the ATQA accordingly - atqa[0] &= 0xBF; - } - - // We need to listen to the high-frequency, peak-detected path. - iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + BigBuf_free_keep_EM(); + clear_trace(); + set_tracing(true); - // allocate buffers: - uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); - uint16_t counter = 0; - - int len = 0; - - BigBuf_free(); - clear_trace(); - set_tracing(true); - - LED_A_ON(); - for (;;) { - WDT_HIT(); - - // Clean receive command buffer - if (!GetIso14443aCommandFromReader(received, receivedPar, &len)) { - Dbprintf("Anti-fuzz stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); - break; - } - p_response = NULL; - - // look at the command now. - if (received[0] == ISO14443A_CMD_REQA) { // Received a REQUEST - p_response = &responses[0]; - } else if (received[0] == ISO14443A_CMD_WUPA) { // Received a WAKEUP - p_response = &responses[0]; - } else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received request for UID (cascade 1) - p_response = &responses[1]; - } else if (received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2) - p_response = &responses[2]; - } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1) - p_response = &responses[3]; - } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2) - p_response = &responses[4]; - } - if (p_response != NULL) { - - EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n); - // do the tracing for the previous reader request and this tag answer: - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - GetParity(p_response->response, p_response->response_n, par); - - EmLogTrace(Uart.output, - Uart.len, - Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, - Uart.parity, - p_response->response, - p_response->response_n, - LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, - (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, - par); - } - counter++; - } + int len = 0; - cmd_send(CMD_ACK,1,0,0,0,0); - switch_off(); - Dbprintf("-[ UID until no response [%d]", counter); -*/ + // allocate buffers: + uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *resp = BigBuf_malloc(20); + + memset(resp, 0xFF, 20); + + LED_A_ON(); + for (;;) { + WDT_HIT(); + + // Clean receive command buffer + if (!GetIso14443aCommandFromReader(received, receivedPar, &len)) { + Dbprintf("Anti-fuzz stopped. Trace length: %d ", BigBuf_get_traceLen()); + break; + } + if (received[0] == ISO14443A_CMD_WUPA || received[0] == ISO14443A_CMD_REQA) { + resp[0] = 0x04; + resp[1] = 0x00; + + if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { + resp[0] = 0x44; + } + + EmSendCmd(resp, 2); + continue; + } + + // Received request for UID (cascade 1) + //if (received[1] >= 0x20 && received[1] <= 0x57 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { + if (received[1] >= 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { + resp[0] = 0xFF; + resp[1] = 0xFF; + resp[2] = 0xFF; + resp[3] = 0xFF; + resp[4] = resp[0] ^ resp[1] ^ resp[2] ^ resp[3]; + colpos = 0; + + if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { + resp[0] = 0x88; + colpos = 8; + } + + EmSendCmdEx(resp, 5, true); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("ANTICOLL or SELECT %x", received[1]); + LED_D_INV(); + + continue; + } else if (received[1] == 0x20 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received request for UID (cascade 2) + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("ANTICOLL or SELECT_2"); + } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) { // Received a SELECT (cascade 1) + } else if (received[1] == 0x70 && received[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) { // Received a SELECT (cascade 2) + } else { + Dbprintf("unknown command %x", received[0]); + } + } + + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + switch_off(); + BigBuf_free_keep_EM(); } static void iso14a_set_ATS_times(uint8_t *ats) { - uint8_t tb1; - uint8_t fwi, sfgi; - uint32_t fwt, sfgt; - - 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]; - } - 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); - } - } - } + if (ats[0] > 1) { // there is a format byte T0 + if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) + uint8_t tb1; + if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) + tb1 = ats[3]; + } else { + tb1 = ats[2]; + } + uint8_t fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) + if (fwi != 15) { + uint32_t fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc + iso14a_set_timeout(fwt / (8 * 16)); + } + uint8_t sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) + if (sfgi != 0 && sfgi != 15) { + uint32_t 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); + } + } + } } 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 +#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; + 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 && GetTickCountDelta(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[] +// 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(byte_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { - - uint8_t sel_all[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x20 }; - uint8_t sel_uid[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t rats[] = { ISO14443A_CMD_RATS,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 - uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller - uint8_t resp_par[MAX_PARITY_SIZE] = {0}; - uint8_t uid_resp[4] = {0}; - size_t uid_resp_len = 0; +int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; - int len; + uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller + uint8_t resp_par[MAX_PARITY_SIZE] = {0}; - if (p_card) { - p_card->uidlen = 0; - memset(p_card->uid, 0, 10); - p_card->ats_len = 0; - } - - if (!GetATQA(resp, resp_par)) { - return 0; - } + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; - if (p_card) { - p_card->atqa[0] = resp[0]; - p_card->atqa[1] = resp[1]; - } + if (p_card) { + p_card->uidlen = 0; + memset(p_card->uid, 0, 10); + p_card->ats_len = 0; + } - 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 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; + if (!GetATQA(resp, resp_par)) { + return 0; + } - if (anticollision) { - // SELECT_ALL - ReaderTransmit(sel_all, sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) return 0; + if (p_card) { + p_card->atqa[0] = resp[0]; + p_card->atqa[1] = resp[1]; + } - 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); - } + if (anticollision) { + // clear uid + if (uid_ptr) + memset(uid_ptr, 0, 10); + } - } 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; + // check for proprietary anticollision: + if ((resp[0] & 0x1F) == 0) return 3; - // calculate crypto UID. Always use last 4 Bytes. - if(cuid_ptr) - *cuid_ptr = bytes_to_num(uid_resp, 4); + // 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) + uint8_t sel_all[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x20 }; + uint8_t sel_uid[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t uid_resp[4] = {0}; + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - // 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 - AddCrc14A(sel_uid, 7); // calculate and add CRC - ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); + if (anticollision) { + // SELECT_ALL + ReaderTransmit(sel_all, sizeof(sel_all), NULL); + if (!ReaderReceive(resp, resp_par)) return 0; - // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return 0; - - sak = resp[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); + } - // 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; - } + } else { // no collision, use the response to SELECT_ALL as current uid + memcpy(uid_resp, resp, 4); + } - if(uid_ptr && anticollision) - memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); + } 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); + } + } + size_t uid_resp_len = 4; - if(p_card) { - memcpy(p_card->uid + (cascade_level*3), uid_resp, uid_resp_len); - p_card->uidlen += uid_resp_len; - } - } + // calculate crypto UID. Always use last 4 Bytes. + if (cuid_ptr) + *cuid_ptr = bytes_to_num(uid_resp, 4); - if (p_card) { - p_card->sak = sak; - } + // 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 + AddCrc14A(sel_uid, 7); // calculate and add CRC + ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); - // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) - if( (sak & 0x20) == 0) return 2; + // Receive the SAK + if (!ReaderReceive(resp, resp_par)) return 0; - // RATS, Request for answer to select - if ( !no_rats ) { + sak = resp[0]; - AddCrc14A(rats, 2); - ReaderTransmit(rats, sizeof(rats), NULL); - len = ReaderReceive(resp, resp_par); - - if (!len) return 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 (p_card) { - memcpy(p_card->ats, resp, sizeof(p_card->ats)); - p_card->ats_len = len; - } + if (uid_ptr && anticollision) + memcpy(uid_ptr + (cascade_level * 3), uid_resp, uid_resp_len); - // reset the PCB block number - iso14_pcb_blocknum = 0; + if (p_card) { + memcpy(p_card->uid + (cascade_level * 3), uid_resp, uid_resp_len); + p_card->uidlen += uid_resp_len; + } + } - // set default timeout and delay next transfer based on ATS - iso14a_set_ATS_times(resp); - } - return 1; + if (p_card) { + p_card->sak = sak; + } + + // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) + if ((sak & 0x20) == 0) return 2; + + // RATS, Request for answer to select + if (!no_rats) { + uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 + AddCrc14A(rats, 2); + ReaderTransmit(rats, sizeof(rats), NULL); + int len = ReaderReceive(resp, resp_par); + + if (!len) return 0; + + if (p_card) { + memcpy(p_card->ats, resp, sizeof(p_card->ats)); + p_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; } int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades) { - uint8_t sel_all[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x20 }; - uint8_t sel_uid[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t resp[5] = {0}; // theoretically. A usual RATS will be much smaller - uint8_t resp_par[1] = {0}; - uint8_t uid_resp[4] = {0}; + uint8_t resp[5] = {0}; // theoretically. A usual RATS will be much smaller + uint8_t resp_par[1] = {0}; + uint8_t uid_resp[4] = {0}; - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; - if (!GetATQA(resp, resp_par)) { - return 0; - } - - // 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; - - 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); - } + if (!GetATQA(resp, resp_par)) { + return 0; + } - // 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 - AddCrc14A(sel_uid, 7); // calculate and add CRC - ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); + // 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++) { + uint8_t sel_all[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x20 }; + uint8_t sel_uid[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return 0; - - sak = resp[0]; + 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); + } - // 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]; - } - } - return 1; + // 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 + AddCrc14A(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]; + } + } + return 1; } void iso14443a_setup(uint8_t fpga_minor_mode) { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Set up the synchronous serial port - FpgaSetupSsc(); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Set up the synchronous serial port + FpgaSetupSsc(); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - LED_D_OFF(); - // Signal field is on with the appropriate LED - if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD || - fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) - LED_D_ON(); + LED_D_OFF(); + // Signal field is on with the appropriate LED + if (fpga_minor_mode == FPGA_HF_ISO14443A_READER_MOD || + fpga_minor_mode == FPGA_HF_ISO14443A_READER_LISTEN) + LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); - SpinDelay(100); - - // Start the timer - StartCountSspClk(); - - // Prepare the demodulation functions - DemodReset(); - UartReset(); - NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER; - iso14a_set_timeout(1060); // 106 * 10ms default + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); + SpinDelay(100); + + // Start the timer + StartCountSspClk(); + + // Prepare the demodulation functions + DemodReset(); + UartReset(); + NextTransferTime = 2 * DELAY_ARM2AIR_AS_READER; + iso14a_set_timeout(1060); // 106 * 10ms default } /* Peter Fillmore 2015 @@ -2208,176 +2376,191 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5 = ACK/NACK Coding of S-block: b8 b7 b6 b5 b4 b3 b2 b1 -1 1 x x x 0 1 0 +1 1 x x x 0 1 0 b5,b6 = 00 - DESELECT - 11 - WTX -*/ -int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { - uint8_t parity[MAX_PARITY_SIZE] = {0x00}; - uint8_t real_cmd[cmd_len+4]; - - // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 - real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) - // put block number into the PCB - real_cmd[0] |= iso14_pcb_blocknum; - memcpy(real_cmd + 1, cmd, cmd_len); - AddCrc14A(real_cmd, cmd_len + 1); - - ReaderTransmit(real_cmd, cmd_len + 3, NULL); + 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] = {0x00}; + uint8_t real_cmd[cmd_len + 4]; - size_t len = ReaderReceive(data, parity); - uint8_t *data_bytes = (uint8_t *) data; + 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; + } + AddCrc14A(real_cmd, cmd_len + 1); - if (!len) { - return 0; //DATA LINK ERROR - } else{ - // S-Block WTX - while((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. - AddCrc14A(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); - } + ReaderTransmit(real_cmd, cmd_len + 3, NULL); - // 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; - } + size_t len = ReaderReceive(data, parity); + uint8_t *data_bytes = (uint8_t *) data; - // crc check - if (len >=3 && !check_crc(CRC_14443_A, data_bytes, len)) { - return -1; - } - - } - - // 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]; - - return len; + 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. + AddCrc14A(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 && !CheckCrc14A(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]; + } + + return len; } //----------------------------------------------------------------------------- // Read an ISO 14443a tag. Send out commands and store answers. //----------------------------------------------------------------------------- -// arg0 iso_14a flags -// arg1 high :: number of bits, if you want to send 7bits etc -// low :: len of commandbytes -// arg2 timeout -// d.asBytes command bytes to send -void ReaderIso14443a(UsbCommand *c) { - iso14a_command_t param = c->arg[0]; - size_t len = c->arg[1] & 0xffff; - size_t lenbits = c->arg[1] >> 16; - uint32_t timeout = c->arg[2]; - uint8_t *cmd = c->d.asBytes; - uint32_t arg0 = 0; - uint8_t buf[USB_CMD_DATA_SIZE] = {0x00}; - uint8_t par[MAX_PARITY_SIZE] = {0x00}; - - if ((param & ISO14A_CONNECT)) - clear_trace(); +// arg0 iso_14a flags +// arg1 high :: number of bits, if you want to send 7bits etc +// low :: len of commandbytes +// arg2 timeout +// d.asBytes command bytes to send +void ReaderIso14443a(PacketCommandNG *c) { + iso14a_command_t param = c->oldarg[0]; + size_t len = c->oldarg[1] & 0xffff; + size_t lenbits = c->oldarg[1] >> 16; + uint32_t timeout = c->oldarg[2]; + uint8_t *cmd = c->data.asBytes; + uint32_t arg0; + uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; + uint8_t par[MAX_PARITY_SIZE] = {0x00}; - set_tracing(true); + if ((param & ISO14A_CONNECT)) + clear_trace(); - if ((param & ISO14A_REQUEST_TRIGGER)) - iso14a_set_trigger(true); + set_tracing(true); - if ((param & ISO14A_CONNECT)) { - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + if ((param & ISO14A_REQUEST_TRIGGER)) + iso14a_set_trigger(true); - // notify client selecting status. - // if failed selecting, turn off antenna and quite. - 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 ); - cmd_send(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); - if ( arg0 == 0 ) - goto OUT; - } - } + if ((param & ISO14A_CONNECT)) { + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if ((param & ISO14A_SET_TIMEOUT)) - iso14a_set_timeout(timeout); + // notify client selecting status. + // if failed selecting, turn off antenna and quite. + 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); + reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); + if (arg0 == 0) + goto OUT; + } + } - if ((param & ISO14A_APDU)) { - arg0 = iso14_apdu(cmd, len, buf); - cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); - } + if ((param & ISO14A_SET_TIMEOUT)) + iso14a_set_timeout(timeout); - if ((param & ISO14A_RAW)) { - - if ((param & ISO14A_APPEND_CRC)) { - // Don't append crc on empty bytearray... - if ( len > 0 ) { - if ((param & ISO14A_TOPAZMODE)) - AddCrc14B(cmd, len); - else - AddCrc14A(cmd, len); + if ((param & ISO14A_APDU)) { + uint8_t res; + arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); + reply_old(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); + } - 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 - } - } - arg0 = ReaderReceive(buf, par); - cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); - } + if ((param & ISO14A_RAW)) { - if ((param & ISO14A_REQUEST_TRIGGER)) - iso14a_set_trigger(false); + if ((param & ISO14A_APPEND_CRC)) { + // Don't append crc on empty bytearray... + if (len > 0) { + if ((param & ISO14A_TOPAZMODE)) + AddCrc14B(cmd, len); + else + AddCrc14A(cmd, len); - if ((param & ISO14A_NO_DISCONNECT)) - return; + len += 2; + if (lenbits) lenbits += 16; + } + } -OUT: - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - set_tracing(false); - LEDsoff(); + 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 + } + } + arg0 = ReaderReceive(buf, par); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + } + + if ((param & ISO14A_REQUEST_TRIGGER)) + iso14a_set_trigger(false); + + if ((param & ISO14A_NO_DISCONNECT)) + return; + +OUT: + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + set_tracing(false); + LEDsoff(); } // Determine the distance between two nonces. @@ -2385,26 +2568,26 @@ OUT: // Therefore try in alternating directions. int32_t dist_nt(uint32_t nt1, uint32_t nt2) { - if (nt1 == nt2) return 0; - - uint32_t nttmp1 = nt1; - uint32_t nttmp2 = nt2; + if (nt1 == nt2) return 0; - for (uint16_t 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; - } - - return(-99999); // either nt1 or nt2 are invalid nonces + uint32_t nttmp1 = nt1; + uint32_t nttmp2 = nt2; + + for (uint16_t 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; + } + + return (-99999); // either nt1 or nt2 are invalid nonces } - -#define PRNG_SEQUENCE_LENGTH (1 << 16) -#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 PRNG_SEQUENCE_LENGTH (1 << 16) +#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 //----------------------------------------------------------------------------- // Recover several bits of the cypher stream. This implements (first stages of) @@ -2412,261 +2595,268 @@ int32_t dist_nt(uint32_t nt1, uint32_t nt2) { // Cloning MiFare Classic Rail and Building Passes, Anywhere, Anytime" // (article by Nicolas T. Courtois, 2009) //----------------------------------------------------------------------------- -void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) { - - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); +void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - uint8_t mf_auth[] = { keytype, block, 0x00, 0x00 }; - uint8_t mf_nr_ar[] = {0,0,0,0,0,0,0,0}; - uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0}; - uint8_t par_list[8] = {0,0,0,0,0,0,0,0}; - uint8_t ks_list[8] = {0,0,0,0,0,0,0,0}; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough - uint8_t nt_diff = 0; + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - uint32_t nt = 0, previous_nt = 0, cuid = 0; - uint32_t sync_time = GetCountSspClk() & 0xfffffff8; - - int32_t catch_up_cycles = 0; - int32_t last_catch_up = 0; - int32_t isOK = 0; - - uint16_t elapsed_prng_sequences = 1; - uint16_t consecutive_resyncs = 0; - uint16_t unexpected_random = 0; - uint16_t sync_tries = 0; + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); - bool have_uid = false; - bool received_nack; - uint8_t cascade_levels = 0; - - // static variables here, is re-used in the next call - static uint32_t nt_attacked = 0; - static int32_t sync_cycles = 0; - static uint8_t par_low = 0; - static uint8_t mf_nr_ar3 = 0; - - AddCrc14A(mf_auth, 2); - - if (first_try) { - sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). - nt_attacked = 0; - mf_nr_ar3 = 0; - par_low = 0; - } else { - // we were unsuccessful on a previous call. - // Try another READER nonce (first 3 parity bits remain the same) - mf_nr_ar3++; - mf_nr_ar[3] = mf_nr_ar3; - par[0] = par_low; - } + uint8_t mf_auth[] = { keytype, block, 0x00, 0x00 }; + uint8_t mf_nr_ar[] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t par_list[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t ks_list[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough + uint8_t nt_diff = 0; - LED_C_ON(); - uint16_t i; - for (i = 0; true; ++i) { + uint32_t nt = 0, previous_nt = 0, cuid = 0; + uint32_t sync_time = GetCountSspClk() & 0xfffffff8; - received_nack = false; - - WDT_HIT(); + int32_t catch_up_cycles = 0; + int32_t last_catch_up = 0; + int32_t isOK = 0; - // Test if the action was cancelled - if (BUTTON_PRESS()) { - isOK = -1; - break; - } - - // this part is from Piwi's faster nonce collecting part in Hardnested. - 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("Mifare: 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_fast_select_card(uid, cascade_levels)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (UID)"); - continue; - } - } + uint16_t elapsed_prng_sequences = 1; + uint16_t consecutive_resyncs = 0; + uint16_t unexpected_random = 0; + uint16_t sync_tries = 0; - elapsed_prng_sequences = 1; - - // Sending timeslot of ISO14443a frame - sync_time = (sync_time & 0xfffffff8 ) + sync_cycles + catch_up_cycles; - catch_up_cycles = 0; + bool have_uid = false; + uint8_t cascade_levels = 0; - #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle - - // 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; - } + // static variables here, is re-used in the next call + static uint32_t nt_attacked = 0; + static int32_t sync_cycles = 0; + static uint8_t par_low = 0; + static uint8_t mf_nr_ar3 = 0; - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) - ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + AddCrc14A(mf_auth, 2); - // Receive the (4 Byte) "random" TAG nonce - if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) - continue; + if (first_try) { + sync_cycles = PRNG_SEQUENCE_LENGTH; // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). + nt_attacked = 0; + mf_nr_ar3 = 0; + par_low = 0; + } else { + // we were unsuccessful on a previous call. + // Try another READER nonce (first 3 parity bits remain the same) + mf_nr_ar3++; + mf_nr_ar[3] = mf_nr_ar3; + par[0] = par_low; + } - previous_nt = nt; - nt = bytes_to_num(receivedAnswer, 4); - - // Transmit reader nonce with fake par - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); + LED_C_ON(); + uint16_t i; + for (i = 0; true; ++i) { - // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding - if (ReaderReceive(receivedAnswer, receivedAnswerPar)) - received_nack = true; + bool received_nack = false; - // we didn't calibrate our clock yet, - // iceman: has to be calibrated every time. - if (previous_nt && !nt_attacked) { + WDT_HIT(); - int nt_distance = dist_nt(previous_nt, nt); - - // if no distance between, then we are in sync. - 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) { - isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly - break; - } - - sync_cycles = (sync_cycles - nt_distance)/elapsed_prng_sequences; - - // no negative sync_cycles - if (sync_cycles <= 0) sync_cycles += PRNG_SEQUENCE_LENGTH; + // Test if the action was cancelled + if (BUTTON_PRESS()) { + isOK = -1; + break; + } - // reset sync_cycles - if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2 ) { - sync_cycles = PRNG_SEQUENCE_LENGTH; - sync_time = GetCountSspClk() & 0xfffffff8; - } - - if (MF_DBGLEVEL >= 4) - 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); + // this part is from Piwi's faster nonce collecting part in Hardnested. + if (!have_uid) { // need a full select cycle to get the uid first + iso14a_card_select_t card_info; + if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Mifare: 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_fast_select_card(uid, cascade_levels)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Mifare: Can't select card (UID)"); + continue; + } + } - LED_B_OFF(); - continue; - } - } - LED_B_OFF(); + elapsed_prng_sequences = 1; - 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. - catch_up_cycles = 0; - continue; - } - // average? - 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; - } - - if (consecutive_resyncs < 3) { - if (MF_DBGLEVEL >= 4) { - 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 { - sync_cycles += catch_up_cycles; - - if (MF_DBGLEVEL >= 4) - 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); + // Sending timeslot of ISO14443a frame + sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; + catch_up_cycles = 0; - last_catch_up = 0; - catch_up_cycles = 0; - consecutive_resyncs = 0; - } - continue; - } - - // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding - if (received_nack) { - 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 +#define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle - par_list[nt_diff] = reflect8(par[0]); - ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // xor with NACK value to get keystream + // 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; + } - // Test if the information is complete - if (nt_diff == 0x07) { - isOK = 1; - break; - } + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); - nt_diff = (nt_diff + 1) & 0x07; - mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5); - par[0] = par_low; - - } else { - // No NACK. - if (nt_diff == 0 && first_try) { - par[0]++; - if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK. - isOK = -2; - break; - } - } else { - // Why this? - par[0] = ((par[0] & 0x1F) + 1) | par_low; - } - } - - // reset the resyncs since we got a complete transaction on right time. - consecutive_resyncs = 0; - } // end for loop + // Receive the (4 Byte) "random" TAG nonce + if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) + continue; - mf_nr_ar[3] &= 0x1F; + previous_nt = nt; + nt = bytes_to_num(receivedAnswer, 4); - if (MF_DBGLEVEL >= 4) Dbprintf("Number of sent auth requestes: %u", i); - - uint8_t buf[32] = {0x00}; - memset(buf, 0x00, sizeof(buf)); - num_to_bytes(cuid, 4, buf); - 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, sizeof(buf) ); + // Transmit reader nonce with fake par + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding + if (ReaderReceive(receivedAnswer, receivedAnswerPar)) + received_nack = true; + + // we didn't calibrate our clock yet, + // iceman: has to be calibrated every time. + if (previous_nt && !nt_attacked) { + + int nt_distance = dist_nt(previous_nt, nt); + + // if no distance between, then we are in sync. + 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) { + isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + break; + } + + sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences; + + // no negative sync_cycles + if (sync_cycles <= 0) sync_cycles += PRNG_SEQUENCE_LENGTH; + + // reset sync_cycles + if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) { + sync_cycles = PRNG_SEQUENCE_LENGTH; + sync_time = GetCountSspClk() & 0xfffffff8; + } + + if (DBGLEVEL >= DBG_EXTENDED) + 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); + + LED_B_OFF(); + continue; + } + } + LED_B_OFF(); + + 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. + catch_up_cycles = 0; + continue; + } + // average? + 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; + } + + if (consecutive_resyncs < 3) { + if (DBGLEVEL >= DBG_EXTENDED) { + 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 { + sync_cycles += catch_up_cycles; + + if (DBGLEVEL >= DBG_EXTENDED) + 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; + } + + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding + if (received_nack) { + 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 + + par_list[nt_diff] = reflect8(par[0]); + ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // xor with NACK value to get keystream + + // Test if the information is complete + if (nt_diff == 0x07) { + isOK = 1; + break; + } + + nt_diff = (nt_diff + 1) & 0x07; + mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5); + par[0] = par_low; + + } else { + // No NACK. + if (nt_diff == 0 && first_try) { + par[0]++; + if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK. + isOK = -2; + break; + } + } else { + // Why this? + par[0] = ((par[0] & 0x1F) + 1) | par_low; + } + } + + // reset the resyncs since we got a complete transaction on right time. + consecutive_resyncs = 0; + } // end for loop + + mf_nr_ar[3] &= 0x1F; + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Number of sent auth requestes: %u", i); + + uint8_t buf[32] = {0x00}; + memset(buf, 0x00, sizeof(buf)); + num_to_bytes(cuid, 4, buf); + 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); + + reply_mix(CMD_ACK, isOK, 0, 0, buf, sizeof(buf)); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); } /* @@ -2674,819 +2864,237 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ) { * Thanks to @doegox for the feedback and new approaches. */ void DetectNACKbug() { - uint8_t mf_auth[] = {0x60, 0x00, 0xF5, 0x7B}; - uint8_t mf_nr_ar[] = {0,0,0,0,0,0,0,0}; - uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0}; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough + uint8_t mf_auth[] = {0x60, 0x00, 0xF5, 0x7B}; + uint8_t mf_nr_ar[] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough - uint32_t nt = 0, previous_nt = 0, nt_attacked = 0, cuid = 0; - int32_t isOK = 0, catch_up_cycles = 0, last_catch_up = 0; - uint8_t cascade_levels = 0, num_nacks = 0; - uint16_t elapsed_prng_sequences = 1; - uint16_t consecutive_resyncs = 0; - uint16_t unexpected_random = 0; - uint16_t sync_tries = 0; - uint32_t sync_time = 0; - bool have_uid = false; - bool received_nack; - - // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). - uint32_t sync_cycles = PRNG_SEQUENCE_LENGTH; + uint32_t nt = 0, previous_nt = 0, nt_attacked = 0, cuid = 0; + int32_t catch_up_cycles = 0, last_catch_up = 0; + uint8_t cascade_levels = 0, num_nacks = 0, isOK = 0; + uint16_t elapsed_prng_sequences = 1; + uint16_t consecutive_resyncs = 0; + uint16_t unexpected_random = 0; + uint16_t sync_tries = 0; + uint32_t sync_time = 0; + bool have_uid = false; - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + int32_t status = PM3_SUCCESS; - sync_time = GetCountSspClk() & 0xfffffff8; - - LED_C_ON(); - uint16_t i; - for (i = 1; true; ++i) { + // Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). + int32_t sync_cycles = PRNG_SEQUENCE_LENGTH; - received_nack = false; - - // Cards always leaks a NACK, no matter the parity - if ((i==10) && (num_nacks == i-1)) { - isOK = 2; - break; - } - - WDT_HIT(); + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - // Test if the action was cancelled - if (BUTTON_PRESS()) { - isOK = 99; - break; - } - - // this part is from Piwi's faster nonce collecting part in Hardnested. - 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("Mifare: 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_fast_select_card(uid, cascade_levels)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card (UID)"); - continue; - } - } + sync_time = GetCountSspClk() & 0xfffffff8; - elapsed_prng_sequences = 1; - - // Sending timeslot of ISO14443a frame - sync_time = (sync_time & 0xfffffff8 ) + sync_cycles + catch_up_cycles; - catch_up_cycles = 0; - - // if we missed the sync time already, advance to the next nonce repeat - while ( GetCountSspClk() > sync_time) { - ++elapsed_prng_sequences; - sync_time = (sync_time & 0xfffffff8 ) + sync_cycles; - } + LED_C_ON(); + uint16_t i; + for (i = 1; true; ++i) { - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) - ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + bool received_nack = false; - // Receive the (4 Byte) "random" TAG nonce - if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) - continue; - - previous_nt = nt; - nt = bytes_to_num(receivedAnswer, 4); - - // Transmit reader nonce with fake par - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); - - if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { - received_nack = true; - num_nacks++; - // ALWAYS leak Detection. - if ( i == num_nacks ) { - continue; - } - } + // Cards always leaks a NACK, no matter the parity + if ((i == 10) && (num_nacks == i - 1)) { + isOK = 2; + break; + } - // we didn't calibrate our clock yet, - // iceman: has to be calibrated every time. - if (previous_nt && !nt_attacked) { + WDT_HIT(); - int nt_distance = dist_nt(previous_nt, nt); - - // if no distance between, then we are in sync. - if (nt_distance == 0) { - nt_attacked = nt; - } else { - if (nt_distance == -99999) { // invalid nonce received - unexpected_random++; - if (unexpected_random > MAX_UNEXPECTED_RANDOM ) { - // Card has an unpredictable PRNG. Give up - isOK = 98; - break; - } else { - if (sync_cycles <= 0) { - sync_cycles += PRNG_SEQUENCE_LENGTH; - } - continue; - } - } - - if (++sync_tries > MAX_SYNC_TRIES) { - isOK = 97; // Card's PRNG runs at an unexpected frequency or resets unexpectedly - break; - } - - sync_cycles = (sync_cycles - nt_distance)/elapsed_prng_sequences; - - if (sync_cycles <= 0) - sync_cycles += PRNG_SEQUENCE_LENGTH; - - if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2 ) { - isOK = 96; // Card's PRNG runs at an unexpected frequency or resets unexpectedly - break; - } - - if (MF_DBGLEVEL >= 4) - 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); + // Test if the action was cancelled + if (BUTTON_PRESS() || data_available()) { + status = PM3_EOPABORTED; + break; + } - continue; - } - } + // this part is from Piwi's faster nonce collecting part in Hardnested. + if (!have_uid) { // need a full select cycle to get the uid first + iso14a_card_select_t card_info; + if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Mifare: Can't select card (ALL)"); + i = 0; + continue; + } + switch (card_info.uidlen) { + case 4 : + cascade_levels = 1; + break; + case 7 : + cascade_levels = 2; + break; + case 10: + cascade_levels = 3; + break; + default: + i = 0; + have_uid = false; + continue; + } + have_uid = true; + } else { // no need for anticollision. We can directly select the card + if (!iso14443a_fast_select_card(uid, cascade_levels)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Mifare: Can't select card (UID)"); + i = 0; + have_uid = false; + continue; + } + } - 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. - catch_up_cycles = 0; - continue; - } - // average? - 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; - } - - if (consecutive_resyncs < 3) { - if (MF_DBGLEVEL >= 4) { - 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 { - sync_cycles += catch_up_cycles; - - if (MF_DBGLEVEL >= 4) { - 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); - Dbprintf("nt [%08x] attacted [%08x]", nt, nt_attacked ); - } - last_catch_up = 0; - catch_up_cycles = 0; - consecutive_resyncs = 0; - } - continue; - } - - // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding - if (received_nack) - catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer + elapsed_prng_sequences = 1; - // we are testing all 256 possibilities. - par[0]++; - - // tried all 256 possible parities without success. - if (par[0] == 0) { - if ( num_nacks == 1 ) - isOK = 1; - break; - } + // Sending timeslot of ISO14443a frame + sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; + catch_up_cycles = 0; - // reset the resyncs since we got a complete transaction on right time. - consecutive_resyncs = 0; - } // end for loop + // if we missed the sync time already, advance to the next nonce repeat + while (GetCountSspClk() > sync_time) { + ++elapsed_prng_sequences; + sync_time = (sync_time & 0xfffffff8) + sync_cycles; + } - // num_nacks = number of nacks recieved. should be only 1. if not its a clone card which always sends NACK (parity == 0) ? - // i = number of authentications sent. Not always 256, since we are trying to sync but close to it. - cmd_send(CMD_ACK, isOK, num_nacks, i, 0, 0 ); + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -/** - *MIFARE 1K simulate. - * - *@param flags : - * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK - * FLAG_4B_UID_IN_DATA - use 4-byte UID in the data-section - * FLAG_7B_UID_IN_DATA - use 7-byte UID in the data-section - * FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section - * FLAG_UID_IN_EMUL - use 4-byte UID from emulator memory - * FLAG_NR_AR_ATTACK - collect NR_AR responses for bruteforcing later - *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite -* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) - */ -void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) { - - int cardSTATE = MFEMUL_NOFIELD; - int _UID_LEN = 0; // 4, 7, 10 - int vHf = 0; // in mV - int res = 0; - uint32_t selTimer = 0; - uint32_t authTimer = 0; - uint16_t len = 0; - uint8_t cardWRBL = 0; - uint8_t cardAUTHSC = 0; - uint8_t cardAUTHKEY = 0xff; // no authentication - uint32_t cuid = 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[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE] = {0x00}; - uint8_t response[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t response_par[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - uint8_t atqa[] = {0x04, 0x00}; // Mifare classic 1k - uint8_t sak_4[] = {0x0C, 0x00, 0x00}; // CL1 - 4b uid - uint8_t sak_7[] = {0x0C, 0x00, 0x00}; // CL2 - 7b uid - uint8_t sak_10[] = {0x0C, 0x00, 0x00}; // CL3 - 10b uid - // uint8_t sak[] = {0x09, 0x3f, 0xcc }; // Mifare Mini - - uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; - uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; - uint8_t rUIDBCC3[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; - - // TAG Nonce - Authenticate response - uint8_t rAUTH_NT[4]; - uint32_t nonce = prng_successor( GetTickCount(), 32 ); - num_to_bytes(nonce, 4, rAUTH_NT); - - // uint8_t rAUTH_NT[] = {0x55, 0x41, 0x49, 0x92};// nonce from nested? why this? - uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - - // Here, we collect CUID, NT, NR, AR, CUID2, NT2, NR2, AR2 - // This can be used in a reader-only attack. - nonces_t ar_nr_nonces[ATTACK_KEY_COUNT]; - memset(ar_nr_nonces, 0x00, sizeof(ar_nr_nonces)); - - // -- Determine the UID - // Can be set from emulator memory or incoming data - // Length: 4,7,or 10 bytes - if ( (flags & FLAG_UID_IN_EMUL) == FLAG_UID_IN_EMUL) - emlGetMemBt(datain, 0, 10); // load 10bytes from EMUL to the datain pointer. to be used below. - - if ( (flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { - memcpy(rUIDBCC1, datain, 4); - _UID_LEN = 4; - } else if ( (flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { - memcpy(&rUIDBCC1[1], datain, 3); - memcpy( rUIDBCC2, datain+3, 4); - _UID_LEN = 7; - } else if ( (flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) { - memcpy(&rUIDBCC1[1], datain, 3); - memcpy(&rUIDBCC2[1], datain+3, 3); - memcpy( rUIDBCC3, datain+6, 4); - _UID_LEN = 10; - } - - switch (_UID_LEN) { - case 4: - sak_4[0] &= 0xFB; - // save CUID - cuid = bytes_to_num(rUIDBCC1, 4); - // BCC - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (MF_DBGLEVEL >= 2) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], - rUIDBCC1[1], - rUIDBCC1[2], - rUIDBCC1[3] - ); - } - break; - case 7: - atqa[0] |= 0x40; - sak_7[0] &= 0xFB; - // save CUID - cuid = bytes_to_num(rUIDBCC2, 4); - // CascadeTag, CT - rUIDBCC1[0] = 0x88; - // BCC - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - if (MF_DBGLEVEL >= 2) { - 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; - case 10: - atqa[0] |= 0x80; - sak_10[0] &= 0xFB; - // save CUID - cuid = bytes_to_num(rUIDBCC3, 4); - // CascadeTag, CT - rUIDBCC1[0] = 0x88; - rUIDBCC2[0] = 0x88; - // BCC - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3]; - - if (MF_DBGLEVEL >= 2) { - Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - rUIDBCC1[1], - rUIDBCC1[2], - rUIDBCC1[3], - rUIDBCC2[1], - rUIDBCC2[2], - rUIDBCC2[3], - rUIDBCC3[0], - rUIDBCC3[1], - rUIDBCC3[2], - rUIDBCC3[3] - ); - } - break; - default: - break; - } - // calc some crcs - compute_crc(CRC_14443_A, sak_4, 1, &sak_4[1], &sak_4[2]); - compute_crc(CRC_14443_A, sak_7, 1, &sak_7[1], &sak_7[2]); - compute_crc(CRC_14443_A, sak_10, 1, &sak_10[1], &sak_10[2]); - - // We need to listen to the high-frequency, peak-detected path. - iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); - - // free eventually allocated BigBuf memory but keep Emulator Memory - BigBuf_free_keep_EM(); - clear_trace(); - set_tracing(true); - LED_D_ON(); - - bool finished = false; - while (!BUTTON_PRESS() && !finished && !usb_poll_validate_length()) { - WDT_HIT(); - - // find reader field - if (cardSTATE == MFEMUL_NOFIELD) { - - vHf = (MAX_ADC_HF_VOLTAGE * 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, receivedCmd_par); - 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 - // this if-statement doesn't match the specification above. (iceman) - if (len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { - selTimer = GetTickCount(); - EmSendCmd(atqa, sizeof(atqa)); - cardSTATE = MFEMUL_SELECT1; - crypto1_destroy(pcs); - cardAUTHKEY = 0xff; - nonce = prng_successor(selTimer, 32); - 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - case MFEMUL_SELECT1:{ - if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received"); - EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); - break; - } - // select card - if (len == 9 && - ( receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && - receivedCmd[1] == 0x70 && - memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { - - // SAK 4b - EmSendCmd(sak_4, sizeof(sak_4)); - switch(_UID_LEN){ - case 4: - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); - continue; - case 7: - case 10: - cardSTATE = MFEMUL_SELECT2; - continue; - default:break; - } - } else { - cardSTATE_TO_IDLE(); - } - break; - } - case MFEMUL_SELECT2:{ - if (!len) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { - EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); - break; - } - if (len == 9 && - (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && - receivedCmd[1] == 0x70 && - memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0) ) { - - EmSendCmd(sak_7, sizeof(sak_7)); - switch(_UID_LEN){ - case 7: - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); - continue; - case 10: - cardSTATE = MFEMUL_SELECT3; - continue; - default:break; - } - } - cardSTATE_TO_IDLE(); - break; - } - case MFEMUL_SELECT3:{ - if (!len) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - if (len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && receivedCmd[1] == 0x20)) { - EmSendCmd(rUIDBCC3, sizeof(rUIDBCC3)); - break; - } - if (len == 9 && - (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3 && - receivedCmd[1] == 0x70 && - memcmp(&receivedCmd[2], rUIDBCC3, 4) == 0) ) { - - EmSendCmd(sak_10, sizeof(sak_10)); - cardSTATE = MFEMUL_WORK; - LED_B_ON(); - if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol3 time: %d", GetTickCount() - selTimer); - break; - } - cardSTATE_TO_IDLE(); - break; - } - case MFEMUL_AUTH1:{ - if( len != 8) { - cardSTATE_TO_IDLE(); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - 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) == FLAG_NR_AR_ATTACK ) { - - int8_t index = -1; - int8_t empty = -1; - for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - // find which index to use - if ( (cardAUTHSC == ar_nr_nonces[i].sector) && (cardAUTHKEY == ar_nr_nonces[i].keytype)) - index = i; - - // keep track of empty slots. - if ( ar_nr_nonces[i].state == EMPTY) - empty = i; - } - // if no empty slots. Choose first and overwrite. - if ( index == -1 ) { - if ( empty == -1 ) { - index = 0; - ar_nr_nonces[index].state = EMPTY; - } else { - index = empty; - } - } - - switch(ar_nr_nonces[index].state) { - case EMPTY: { - // first nonce collect - ar_nr_nonces[index].cuid = cuid; - ar_nr_nonces[index].sector = cardAUTHSC; - ar_nr_nonces[index].keytype = cardAUTHKEY; - ar_nr_nonces[index].nonce = nonce; - ar_nr_nonces[index].nr = nr; - ar_nr_nonces[index].ar = ar; - ar_nr_nonces[index].state = FIRST; - break; - } - case FIRST : { - // second nonce collect - ar_nr_nonces[index].nonce2 = nonce; - ar_nr_nonces[index].nr2 = nr; - ar_nr_nonces[index].ar2 = ar; - ar_nr_nonces[index].state = SECOND; - - // send to client - cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, 0, 0, &ar_nr_nonces[index], sizeof(nonces_t)); - - ar_nr_nonces[index].state = EMPTY; - ar_nr_nonces[index].sector = 0; - ar_nr_nonces[index].keytype = 0; - break; - } - default: break; - } - } - - crypto1_word(pcs, nr , 1); - uint32_t cardRr = ar ^ crypto1_word(pcs, 0, 0); - - //test if auth OK - if (cardRr != prng_successor(nonce, 64)){ - - if (MF_DBGLEVEL >= 3) { - Dbprintf("AUTH FAILED for sector %d with key %c. [nr=%08x cardRr=%08x] [nt=%08x succ=%08x]" - , cardAUTHSC - , (cardAUTHKEY == 0) ? 'A' : 'B' - , nr - , cardRr - , nonce // nt - , 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 - cardSTATE_TO_IDLE(); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - - ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); - num_to_bytes(ans, 4, rAUTH_AT); - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); - LED_C_ON(); - - if (MF_DBGLEVEL >= 3) { - Dbprintf("AUTH COMPLETED for sector %d with key %c. time=%d", - cardAUTHSC, - cardAUTHKEY == 0 ? 'A' : 'B', - GetTickCount() - authTimer - ); - } - cardSTATE = MFEMUL_WORK; - break; - } - case MFEMUL_WORK:{ - if (len == 0) { - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - bool encrypted_data = (cardAUTHKEY != 0xFF) ; - - if(encrypted_data) - mf_crypto1_decrypt(pcs, receivedCmd, len); - - if (len == 4 && (receivedCmd[0] == MIFARE_AUTH_KEYA || - receivedCmd[0] == MIFARE_AUTH_KEYB) ) { - - authTimer = GetTickCount(); - cardAUTHSC = receivedCmd[1] / 4; // received block -> sector - cardAUTHKEY = receivedCmd[0] & 0x1; - crypto1_destroy(pcs); - - // load key into crypto - crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); - - if (!encrypted_data) { - // first authentication - // Update crypto state init (UID ^ NONCE) - crypto1_word(pcs, cuid ^ nonce, 0); - num_to_bytes(nonce, 4, rAUTH_AT); - } else { - // nested authentication - ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0); - num_to_bytes(ans, 4, rAUTH_AT); - - if (MF_DBGLEVEL >= 3) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %c", receivedCmd[1], receivedCmd[1], cardAUTHKEY == 0 ? 'A' : 'B'); - } - - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); - 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - - if ( receivedCmd[0] == ISO14443A_CMD_READBLOCK || - receivedCmd[0] == ISO14443A_CMD_WRITEBLOCK || - receivedCmd[0] == MIFARE_CMD_INC || - receivedCmd[0] == MIFARE_CMD_DEC || - receivedCmd[0] == MIFARE_CMD_RESTORE || - receivedCmd[0] == MIFARE_CMD_TRANSFER ) { - - if (receivedCmd[1] >= 16 * 4) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 4) 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 >= 4) 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] == ISO14443A_CMD_READBLOCK) { - if (MF_DBGLEVEL >= 4) Dbprintf("Reader reading block %d (0x%02x)", receivedCmd[1], receivedCmd[1]); - - emlGetMem(response, receivedCmd[1], 1); - AddCrc14A(response, 16); - mf_crypto1_encrypt(pcs, response, 18, response_par); - EmSendCmdPar(response, 18, response_par); - numReads++; - if(exitAfterNReads > 0 && numReads >= exitAfterNReads) { - Dbprintf("%d reads done, exiting", numReads); - finished = true; - } - break; - } - // write block - if (receivedCmd[0] == ISO14443A_CMD_WRITEBLOCK) { - if (MF_DBGLEVEL >= 4) 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] == MIFARE_CMD_INC || - receivedCmd[0] == MIFARE_CMD_DEC || - receivedCmd[0] == MIFARE_CMD_RESTORE) { - - if (MF_DBGLEVEL >= 4) 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 >= 4) 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] == MIFARE_CMD_INC) cardSTATE = MFEMUL_INTREG_INC; - if (receivedCmd[0] == MIFARE_CMD_DEC) cardSTATE = MFEMUL_INTREG_DEC; - if (receivedCmd[0] == MIFARE_CMD_RESTORE) cardSTATE = MFEMUL_INTREG_REST; - cardWRBL = receivedCmd[1]; - break; - } - // transfer - if (receivedCmd[0] == MIFARE_CMD_TRANSFER) { - if (MF_DBGLEVEL >= 4) 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] == ISO14443A_CMD_HALT && 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - break; - } - // RATS - if (receivedCmd[0] == ISO14443A_CMD_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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, 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.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); - cardSTATE = MFEMUL_WORK; - break; - } - } - } - - if (MF_DBGLEVEL >= 1) - Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); - - cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); + // Receive the (4 Byte) "random" TAG nonce + if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) + continue; + + previous_nt = nt; + nt = bytes_to_num(receivedAnswer, 4); + + // Transmit reader nonce with fake par + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); + + if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { + received_nack = true; + num_nacks++; + // ALWAYS leak Detection. + if (i == num_nacks) { + continue; + } + } + + // we didn't calibrate our clock yet, + // iceman: has to be calibrated every time. + if (previous_nt && !nt_attacked) { + + int nt_distance = dist_nt(previous_nt, nt); + + // if no distance between, then we are in sync. + if (nt_distance == 0) { + nt_attacked = nt; + } else { + if (nt_distance == -99999) { // invalid nonce received + unexpected_random++; + if (unexpected_random > MAX_UNEXPECTED_RANDOM) { + // Card has an unpredictable PRNG. Give up + isOK = 98; + break; + } else { + if (sync_cycles <= 0) { + sync_cycles += PRNG_SEQUENCE_LENGTH; + } + continue; + } + } + + if (++sync_tries > MAX_SYNC_TRIES) { + isOK = 97; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + break; + } + + sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences; + + if (sync_cycles <= 0) + sync_cycles += PRNG_SEQUENCE_LENGTH; + + if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) { + isOK = 96; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + break; + } + + if (DBGLEVEL >= DBG_EXTENDED) + 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); + + continue; + } + } + + 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. + catch_up_cycles = 0; + continue; + } + // average? + 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; + } + + if (consecutive_resyncs < 3) { + if (DBGLEVEL >= DBG_EXTENDED) { + 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 { + sync_cycles += catch_up_cycles; + + if (DBGLEVEL >= DBG_EXTENDED) { + 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); + Dbprintf("nt [%08x] attacted [%08x]", nt, nt_attacked); + } + last_catch_up = 0; + catch_up_cycles = 0; + consecutive_resyncs = 0; + } + continue; + } + + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding + if (received_nack) + catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer + + // we are testing all 256 possibilities. + par[0]++; + + // tried all 256 possible parities without success. + if (par[0] == 0) { + // did we get one NACK? + if (num_nacks == 1) + isOK = 1; + break; + } + + // reset the resyncs since we got a complete transaction on right time. + consecutive_resyncs = 0; + } // end for loop + + // num_nacks = number of nacks recieved. should be only 1. if not its a clone card which always sends NACK (parity == 0) ? + // i = number of authentications sent. Not always 256, since we are trying to sync but close to it. + + uint8_t *data = BigBuf_malloc(4); + data[0] = isOK; + data[1] = num_nacks; + num_to_bytes(i, 2, data + 2); + reply_ng(CMD_MIFARE_NACK_DETECT, status, data, 4); + + //reply_mix(CMD_ACK, isOK, num_nacks, i, 0, 0); + BigBuf_free(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index ff9116d67..5ebc3e645 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -16,8 +16,8 @@ #ifdef __cplusplus extern "C" { #endif - -#include "usb_cmd.h" + +#include "pm3_cmd.h" #include "cmd.h" #include "apps.h" #include "util.h" @@ -27,115 +27,131 @@ extern "C" { #include "crapto1/crapto1.h" #include "mifareutil.h" #include "parity.h" -#include "random.h" #include "mifare.h" // structs +// When the PM acts as tag and is receiving it takes +// 2 ticks delay in the RF part (for the first falling edge), +// 3 ticks for the A/D conversion, +// 8 ticks on average until the start of the SSC transfer, +// 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 +#define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16) + 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; + 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; + 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; + 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; + uint8_t *parity; } tUart; #ifndef AddCrc14A -# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) +# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) #endif #ifndef AddCrc14B -# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1) +# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1) #endif -extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); +#ifndef CheckCrc14A +# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) +#endif -extern tDemod* GetDemod(void); -extern void DemodReset(void); -extern void DemodInit(uint8_t *data, uint8_t *parity); -extern tUart* GetUart(void); -extern void UartReset(void); -extern void UartInit(uint8_t *data, uint8_t *parity); -extern RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time); -extern RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time); +void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); -extern void RAMFUNC SniffIso14443a(uint8_t param); -extern void SimulateIso14443aTag(int tagType, int flags, uint8_t *data); -extern void iso14443a_antifuzz(uint32_t flags); -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); +tDemod *GetDemod(void); +void DemodReset(void); +void DemodInit(uint8_t *data, uint8_t *par); +tUart *GetUart(void); +void UartReset(void); +void UartInit(uint8_t *data, uint8_t *par); +RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time); +RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time); -extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); -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 iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); -extern void iso14a_set_trigger(bool enable); +void RAMFUNC SniffIso14443a(uint8_t param); +void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data); +void iso14443a_antifuzz(uint32_t flags); +void ReaderIso14443a(PacketCommandNG *c); +void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); +void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); +void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); +int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); -extern int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen); -extern int EmSend4bit(uint8_t resp); -extern int EmSendCmd(uint8_t *resp, uint16_t respLen); -extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity); -extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); -extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); +void iso14443a_setup(uint8_t fpga_minor_mode); +int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); +int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); +int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); +void iso14a_set_trigger(bool enable); + +int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen); +int EmSend4bit(uint8_t resp); +int EmSendCmd(uint8_t *resp, uint16_t respLen); +int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision); +int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par); +int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); +int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision); +int EmSendPrecompiledCmd(tag_response_info_t *p_response); + +bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *max_buffer_size); bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, - uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity); + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity); -//extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size); - -void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype ); +void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype); void DetectNACKbug(); #ifdef __cplusplus } -#endif +#endif #endif /* __ISO14443A_H */ diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index edf114134..241484d01 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -38,9 +38,9 @@ // 4sample #define SEND4STUFFBIT(x) ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x);ToSendStuffBit(x); //#define SEND4STUFFBIT(x) ToSendStuffBit(x); - // iceman, this threshold value, what makes 8 a good amplitude for this IQ values? +// iceman, this threshold value, what makes 8 a good amplitude for this IQ values? #ifndef SUBCARRIER_DETECT_THRESHOLD -# define SUBCARRIER_DETECT_THRESHOLD 8 +# define SUBCARRIER_DETECT_THRESHOLD 8 #endif static void iso14b_set_timeout(uint32_t timeout); @@ -63,110 +63,110 @@ static uint32_t iso14b_timeout = FWT_TIMEOUT_14B; // 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; + 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; static void UartReset() { - Uart.state = STATE_UNSYNCD; - Uart.shiftReg = 0; - Uart.bitCnt = 0; - Uart.byteCnt = 0; - Uart.byteCntMax = MAX_FRAME_SIZE; - Uart.posCnt = 0; + Uart.state = STATE_UNSYNCD; + Uart.shiftReg = 0; + Uart.bitCnt = 0; + Uart.byteCnt = 0; + Uart.byteCntMax = MAX_FRAME_SIZE; + Uart.posCnt = 0; } static void UartInit(uint8_t *data) { - Uart.output = data; - UartReset(); -// memset(Uart.output, 0x00, MAX_FRAME_SIZE); + Uart.output = data; + UartReset(); +// memset(Uart.output, 0x00, MAX_FRAME_SIZE); } //----------------------------------------------------------------------------- // The software Demod that receives commands from the tag, and its state variables. //----------------------------------------------------------------------------- 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; - uint16_t 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; - uint16_t len; - int sumI; - int sumQ; - uint32_t startTime, endTime; + 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; + uint16_t 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; + uint16_t len; + int sumI; + int sumQ; + uint32_t startTime, endTime; } Demod; // Clear out the state of the "UART" that receives from the tag. static void DemodReset() { - Demod.state = DEMOD_UNSYNCD; - Demod.bitCount = 0; - Demod.posCount = 0; - Demod.thisBit = 0; - Demod.shiftReg = 0; - Demod.len = 0; - Demod.sumI = 0; - Demod.sumQ = 0; - Demod.startTime = 0; - Demod.endTime = 0; + Demod.state = DEMOD_UNSYNCD; + Demod.bitCount = 0; + Demod.posCount = 0; + Demod.thisBit = 0; + Demod.shiftReg = 0; + Demod.len = 0; + Demod.sumI = 0; + Demod.sumQ = 0; + Demod.startTime = 0; + Demod.endTime = 0; } static void DemodInit(uint8_t *data) { - Demod.output = data; - DemodReset(); - // memset(Demod.output, 0x00, MAX_FRAME_SIZE); + Demod.output = data; + DemodReset(); + // memset(Demod.output, 0x00, MAX_FRAME_SIZE); } /* * 9.4395 us = 1 ETU and clock is about 1.5 us -* 13560000Hz +* 13560000Hz * 1000ms/s * timeout in ETUs (time to transfer 1 bit, 9.4395 us) * * Formula to calculate FWT (in ETUs) by timeout (in ms): -* fwt = 13560000 * 1000 / (8*16) * timeout; +* fwt = 13560000 * 1000 / (8*16) * timeout; * Sample: 3sec == 3000ms -* 13560000 * 1000 / (8*16) * 3000 == +* 13560000 * 1000 / (8*16) * 3000 == * 13560000000 / 384000 = 35312 FWT * @param timeout is in frame wait time, fwt, measured in ETUs -*/ +*/ static void iso14b_set_timeout(uint32_t timeout) { - #define MAX_TIMEOUT 40542464 // 13560000Hz * 1000ms / (2^32-1) * (8*16) - if(timeout > MAX_TIMEOUT) - timeout = MAX_TIMEOUT; +#define MAX_TIMEOUT 40542464 // 13560000Hz * 1000ms / (2^32-1) * (8*16) + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; - iso14b_timeout = timeout; - if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout); + iso14b_timeout = timeout; + if (DBGLEVEL >= 3) Dbprintf("ISO14443B Timeout set to %ld fwt", iso14b_timeout); } static void iso14b_set_maxframesize(uint16_t size) { - if (size > 256) - size = MAX_FRAME_SIZE; - - Uart.byteCntMax = size; - if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443B Max frame size set to %d bytes", Uart.byteCntMax); + if (size > 256) + size = MAX_FRAME_SIZE; + + Uart.byteCntMax = size; + if (DBGLEVEL >= 3) Dbprintf("ISO14443B Max frame size set to %d bytes", Uart.byteCntMax); } //----------------------------------------------------------------------------- @@ -175,132 +175,129 @@ static void iso14b_set_maxframesize(uint16_t size) { // them yet, just leaves them ready to send in ToSend[]. //----------------------------------------------------------------------------- static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { - /* ISO 14443 B - * - * Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig) - * Card to reader | BPSK - Binary Phase Shift Keying Modulation, (PICC to PCD for Type B) - * - * fc - carrier frequency 13.56mHz - * TR0 - Guard Time per 14443-2 - * TR1 - Synchronization Time per 14443-2 - * TR2 - PICC to PCD Frame Delay Time (per 14443-3 Amendment 1) - * - * Elementary Time Unit (ETU) is - * - 128 Carrier Cycles (9.4395 µS) = 8 Subcarrier Units - * - 1 ETU = 1 bit - * - 10 ETU = 1 startbit, 8 databits, 1 stopbit (10bits length) - * - startbit is a 0 - * - stopbit is a 1 - * - * Start of frame (SOF) is - * - [10-11] ETU of ZEROS, unmodulated time - * - [2-3] ETU of ONES, - * - * End of frame (EOF) is - * - [10-11] ETU of ZEROS, unmodulated time - * - * -TO VERIFY THIS BELOW- - * The mode FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK which we use to simulate tag - * works like this: - * - A 1-bit input to the FPGA becomes 8 pulses at 847.5kHz (1.18µS / pulse) == 9.44us - * - A 0-bit input to the FPGA becomes an unmodulated time of 1.18µS or does it become 8 nonpulses for 9.44us - * - * FPGA doesn't seem to work with ETU. It seems to work with pulse / duration instead. - * - * Card sends data ub 847.e kHz subcarrier - * subcar |duration| FC division - * -------+--------+------------ - * 106kHz | 9.44µS | FC/128 - * 212kHz | 4.72µS | FC/64 - * 424kHz | 2.36µS | FC/32 - * 848kHz | 1.18µS | FC/16 - * -------+--------+------------ - * - * Reader data transmission: - * - no modulation ONES - * - SOF - * - Command, data and CRC_B - * - EOF - * - no modulation ONES - * - * Card data transmission - * - TR1 - * - SOF - * - data (each bytes is: 1startbit, 8bits, 1stopbit) - * - CRC_B - * - EOF - * - * FPGA implementation : - * At this point only Type A is implemented. This means that we are using a - * bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make - * things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s) - * - */ - - int i,j; - uint8_t b; - - ToSendReset(); + /* ISO 14443 B + * + * Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig) + * Card to reader | BPSK - Binary Phase Shift Keying Modulation, (PICC to PCD for Type B) + * + * fc - carrier frequency 13.56 MHz + * TR0 - Guard Time per 14443-2 + * TR1 - Synchronization Time per 14443-2 + * TR2 - PICC to PCD Frame Delay Time (per 14443-3 Amendment 1) + * + * Elementary Time Unit (ETU) is + * - 128 Carrier Cycles (9.4395 µS) = 8 Subcarrier Units + * - 1 ETU = 1 bit + * - 10 ETU = 1 startbit, 8 databits, 1 stopbit (10bits length) + * - startbit is a 0 + * - stopbit is a 1 + * + * Start of frame (SOF) is + * - [10-11] ETU of ZEROS, unmodulated time + * - [2-3] ETU of ONES, + * + * End of frame (EOF) is + * - [10-11] ETU of ZEROS, unmodulated time + * + * -TO VERIFY THIS BELOW- + * The mode FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK which we use to simulate tag + * works like this: + * - A 1-bit input to the FPGA becomes 8 pulses at 847.5kHz (1.18µS / pulse) == 9.44us + * - A 0-bit input to the FPGA becomes an unmodulated time of 1.18µS or does it become 8 nonpulses for 9.44us + * + * FPGA doesn't seem to work with ETU. It seems to work with pulse / duration instead. + * + * Card sends data ub 847.e kHz subcarrier + * subcar |duration| FC division + * -------+--------+------------ + * 106kHz | 9.44µS | FC/128 + * 212kHz | 4.72µS | FC/64 + * 424kHz | 2.36µS | FC/32 + * 848kHz | 1.18µS | FC/16 + * -------+--------+------------ + * + * Reader data transmission: + * - no modulation ONES + * - SOF + * - Command, data and CRC_B + * - EOF + * - no modulation ONES + * + * Card data transmission + * - TR1 + * - SOF + * - data (each bytes is: 1startbit, 8bits, 1stopbit) + * - CRC_B + * - EOF + * + * FPGA implementation : + * At this point only Type A is implemented. This means that we are using a + * bit rate of 106 kbit/s, or fc/128. Oversample by 4, which ought to make + * things practical for the ARM (fc/32, 423.8 kbits/s, ~50 kbytes/s) + * + */ - // Transmit a burst of ones, as the initial thing that lets the - // reader get phase sync. - // This loop is TR1, per specification - // TR1 minimum must be > 80/fs - // TR1 maximum 200/fs - // 80/fs < TR1 < 200/fs - // 10 ETU < TR1 < 24 ETU + ToSendReset(); - // Send SOF. - // 10-11 ETU * 4times samples ZEROS - for(i = 0; i < 10; i++) { SEND4STUFFBIT(0); } - //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } - - // 2-3 ETU * 4times samples ONES - for(i = 0; i < 3; i++) { SEND4STUFFBIT(1); } - //for(i = 0; i < 3; i++) { ToSendStuffBit(1); } - - // data - for(i = 0; i < len; ++i) { - - // Start bit - SEND4STUFFBIT(0); - //ToSendStuffBit(0); + // Transmit a burst of ones, as the initial thing that lets the + // reader get phase sync. + // This loop is TR1, per specification + // TR1 minimum must be > 80/fs + // TR1 maximum 200/fs + // 80/fs < TR1 < 200/fs + // 10 ETU < TR1 < 24 ETU - // Data bits - b = cmd[i]; - for(j = 0; j < 8; ++j) { - // if(b & 1) { - // SEND4STUFFBIT(1); - // //ToSendStuffBit(1); - // } else { - // SEND4STUFFBIT(0); - // //ToSendStuffBit(0); - // } - SEND4STUFFBIT( b & 1 ); - b >>= 1; - } + // Send SOF. + // 10-11 ETU * 4times samples ZEROS + for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } + //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } - // Stop bit - SEND4STUFFBIT(1); - //ToSendStuffBit(1); - - // Extra Guard bit - // For PICC it ranges 0-18us (1etu = 9us) - SEND4STUFFBIT(1); - //ToSendStuffBit(1); - } + // 2-3 ETU * 4times samples ONES + for (int i = 0; i < 3; i++) { SEND4STUFFBIT(1); } + //for(i = 0; i < 3; i++) { ToSendStuffBit(1); } - // Send EOF. - // 10-11 ETU * 4 sample rate = ZEROS - for(i = 0; i < 10; i++) { SEND4STUFFBIT(0); } - //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } - - // why this? - for(i = 0; i < 40; i++) { SEND4STUFFBIT(1); } - //for(i = 0; i < 40; i++) { ToSendStuffBit(1); } - - // Convert from last byte pos to length - ++ToSendMax; + // data + for (int i = 0; i < len; ++i) { + + // Start bit + SEND4STUFFBIT(0); + //ToSendStuffBit(0); + + // Data bits + uint8_t b = cmd[i]; + for (int j = 0; j < 8; ++j) { + // if(b & 1) { + // SEND4STUFFBIT(1); + // //ToSendStuffBit(1); + // } else { + // SEND4STUFFBIT(0); + // //ToSendStuffBit(0); + // } + SEND4STUFFBIT(b & 1); + b >>= 1; + } + + // Stop bit + SEND4STUFFBIT(1); + //ToSendStuffBit(1); + + // Extra Guard bit + // For PICC it ranges 0-18us (1etu = 9us) + SEND4STUFFBIT(1); + //ToSendStuffBit(1); + } + + // Send EOF. + // 10-11 ETU * 4 sample rate = ZEROS + for (int i = 0; i < 10; i++) { SEND4STUFFBIT(0); } + //for(i = 0; i < 10; i++) { ToSendStuffBit(0); } + + // why this? + for (int i = 0; i < 40; i++) { SEND4STUFFBIT(1); } + //for(i = 0; i < 40; i++) { ToSendStuffBit(1); } + + // Convert from last byte pos to length + ++ToSendMax; } @@ -317,111 +314,110 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) { * false if we are still waiting for some more */ static RAMFUNC int Handle14443bReaderUartBit(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; + 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_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_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++; + 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; + 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; - default: - LED_A_OFF(); - Uart.state = STATE_UNSYNCD; - break; - } - return false; + } else { + // this is an error + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + } + } + break; + + default: + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; + break; + } + return false; } //----------------------------------------------------------------------------- @@ -434,284 +430,290 @@ static RAMFUNC int Handle14443bReaderUartBit(uint8_t bit) { // 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); - - StartCountSspClk(); - - volatile uint8_t b = 0; + // 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); - // clear receiving shift register and holding register - // What does this loop do? Is it TR1? - // loop is a wait/delay ? -/* - for(uint8_t c = 0; c < 10;) { + StartCountSspClk(); - // keep tx buffer in a defined state anyway. - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - ++c; - } - } - */ - // Now run a `software UART' on the stream of incoming samples. - UartInit(received); + volatile uint8_t b; - uint8_t mask; - while( !BUTTON_PRESS() ) { - WDT_HIT(); + // clear receiving shift register and holding register + // What does this loop do? Is it TR1? + // loop is a wait/delay ? + /* + for(uint8_t c = 0; c < 10;) { - // keep tx buffer in a defined state anyway. - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } + // keep tx buffer in a defined state anyway. + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xFF; + ++c; + } + } + */ + // Now run a `software UART' on the stream of incoming samples. + UartInit(received); - // Wait for byte be become available in rx holding register - if ( AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY ) { - - b = (uint8_t) AT91C_BASE_SSC->SSC_RHR; - - for ( mask = 0x80; mask != 0; mask >>= 1) { - if ( Handle14443bReaderUartBit(b & mask)) { - *len = Uart.byteCnt; - return true; - } - } - } - } - return false; + uint8_t mask; + while (!BUTTON_PRESS()) { + WDT_HIT(); + + // keep tx buffer in a defined state anyway. + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + + // Wait for byte be become available in rx holding register + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + + b = (uint8_t) AT91C_BASE_SSC->SSC_RHR; + + for (mask = 0x80; mask != 0; mask >>= 1) { + if (Handle14443bReaderUartBit(b & mask)) { + *len = Uart.byteCnt; + return true; + } + } + } + } + return false; } -void ClearFpgaShiftingRegisters(void){ +void ClearFpgaShiftingRegisters(void) { - volatile uint8_t b; + volatile uint8_t b; - // clear receiving shift register and holding register - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) {}; + // clear receiving shift register and holding register + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) {}; - b = AT91C_BASE_SSC->SSC_RHR; (void) b; + 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 (uint8_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; - } - - // Clear TXRDY: - //AT91C_BASE_SSC->SSC_THR = 0xFF; + 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 (uint8_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; + } + + // Clear TXRDY: + //AT91C_BASE_SSC->SSC_THR = 0xFF; } -void WaitForFpgaDelayQueueIsEmpty( uint16_t delay ){ - // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: - uint8_t fpga_queued_bits = delay >> 3; // twich /8 ?? >>3, - for (uint8_t i = 0; i <= fpga_queued_bits/8 + 1; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - i++; - } - } +void WaitForFpgaDelayQueueIsEmpty(uint16_t delay) { + // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: + uint8_t fpga_queued_bits = delay >> 3; // twich /8 ?? >>3, + for (uint8_t i = 0; i <= fpga_queued_bits / 8 + 1;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xFF; + i++; + } + } } -static void TransmitFor14443b_AsTag( uint8_t *response, uint16_t len) { +static void TransmitFor14443b_AsTag(uint8_t *response, uint16_t len) { - volatile uint32_t b; - - // Signal field is off with the appropriate LED - LED_D_OFF(); - //uint16_t fpgasendQueueDelay = 0; - - // Modulate BPSK - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); - SpinDelay(40); - - ClearFpgaShiftingRegisters(); - - FpgaSetupSsc(); + volatile uint32_t b; - // Transmit the response. - for(uint16_t i = 0; i < len;) { - - // Put byte into tx holding register as soon as it is ready - if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = response[++i]; - } - - // Prevent rx holding register from overflowing - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = AT91C_BASE_SSC->SSC_RHR;(void)b; - } - } - - //WaitForFpgaDelayQueueIsEmpty(fpgasendQueueDelay); - AT91C_BASE_SSC->SSC_THR = 0xFF; -} + // Signal field is off with the appropriate LED + LED_D_OFF(); + //uint16_t fpgasendQueueDelay = 0; + + // Modulate BPSK + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); + SpinDelay(40); + + ClearFpgaShiftingRegisters(); + + FpgaSetupSsc(); + + // Transmit the response. + for (uint16_t i = 0; i < len;) { + + // Put byte into tx holding register as soon as it is ready + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = response[++i]; + } + + // Prevent rx holding register from overflowing + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + } + + //WaitForFpgaDelayQueueIsEmpty(fpgasendQueueDelay); + AT91C_BASE_SSC->SSC_THR = 0xFF; +} //----------------------------------------------------------------------------- // Main loop of simulated tag: receive commands from reader, decide what // response to send, and send it. //----------------------------------------------------------------------------- void SimulateIso14443bTag(uint32_t pupi) { - // setup device. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Set up the synchronous serial port - FpgaSetupSsc(); - - // allocate command receive buffer - BigBuf_free(); BigBuf_Clear_ext(false); + // setup device. + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // Set up the synchronous serial port + FpgaSetupSsc(); - clear_trace(); //sim - set_tracing(true); + // allocate command receive buffer + BigBuf_free(); + BigBuf_Clear_ext(false); - uint16_t len, cmdsReceived = 0; - int cardSTATE = SIM_NOFIELD; - int vHf = 0; // in mV - // uint32_t time_0 = 0; - // uint32_t t2r_time = 0; - // uint32_t r2t_time = 0; - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - - // the only commands we understand is WUPB, AFI=0, Select All, N=1: -// static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB - // ... and REQB, AFI=0, Normal Request, N=1: -// static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB - // ... and ATTRIB -// static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB + clear_trace(); //sim + set_tracing(true); - // ... if not PUPI/UID is supplied 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: - uint8_t respATQB[] = { 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, - 0x22, 0x00, 0x21, 0x85, 0x5e, 0xd7 }; - - // response to HLTB and ATTRIB - static const uint8_t respOK[] = {0x00, 0x78, 0xF0}; + uint16_t len, cmdsReceived = 0; + int cardSTATE = SIM_NOFIELD; + int vHf = 0; // in mV + // uint32_t time_0 = 0; + // uint32_t t2r_time = 0; + // uint32_t r2t_time = 0; + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - // ...PUPI/UID supplied from user. Adjust ATQB response accordingly - if ( pupi > 0 ) { - num_to_bytes(pupi, 4, respATQB+1); - AddCrc14B(respATQB, 12); - } + // the only commands we understand is WUPB, AFI=0, Select All, N=1: +// static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB + // ... and REQB, AFI=0, Normal Request, N=1: +// static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB + // ... and ATTRIB +// static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB - // prepare "ATQB" tag answer (encoded): - CodeIso14443bAsTag(respATQB, sizeof(respATQB)); - uint8_t *encodedATQB = BigBuf_malloc(ToSendMax); - uint16_t encodedATQBLen = ToSendMax; - memcpy(encodedATQB, ToSend, ToSendMax); + // ... if not PUPI/UID is supplied 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: + uint8_t respATQB[] = { 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, + 0x22, 0x00, 0x21, 0x85, 0x5e, 0xd7 + }; - - // prepare "OK" tag answer (encoded): - CodeIso14443bAsTag(respOK, sizeof(respOK)); - uint8_t *encodedOK = BigBuf_malloc(ToSendMax); - uint16_t encodedOKLen = ToSendMax; - memcpy(encodedOK, ToSend, ToSendMax); - - // Simulation loop - while (!BUTTON_PRESS() && !usb_poll_validate_length()) { - WDT_HIT(); + // response to HLTB and ATTRIB + static const uint8_t respOK[] = {0x00, 0x78, 0xF0}; - // find reader field - if (cardSTATE == SIM_NOFIELD) { - vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; - if ( vHf > MF_MINFIELDV ) { - cardSTATE = SIM_IDLE; - LED_A_ON(); - } - } - if (cardSTATE == SIM_NOFIELD) continue; + // ...PUPI/UID supplied from user. Adjust ATQB response accordingly + if (pupi > 0) { + num_to_bytes(pupi, 4, respATQB + 1); + AddCrc14B(respATQB, 12); + } - // Get reader command - if (!GetIso14443bCommandFromReader(receivedCmd, &len)) { - Dbprintf("button pressed, received %d commands", cmdsReceived); - break; - } + // prepare "ATQB" tag answer (encoded): + CodeIso14443bAsTag(respATQB, sizeof(respATQB)); + uint8_t *encodedATQB = BigBuf_malloc(ToSendMax); + uint16_t encodedATQBLen = ToSendMax; + memcpy(encodedATQB, ToSend, ToSendMax); - // ISO14443-B protocol states: - // REQ or WUP request in ANY state - // WUP in HALTED state - if (len == 5 ) { - if ( (receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8)== 0x8 && cardSTATE == SIM_HALTED) || - receivedCmd[0] == ISO14443B_REQB ){ - LogTrace(receivedCmd, len, 0, 0, NULL, true); - cardSTATE = SIM_SELECTING; - } - } - - /* - * How should this flow go? - * REQB or WUPB - * send response ( waiting for Attrib) - * ATTRIB - * send response ( waiting for commands 7816) - * HALT - send halt response ( waiting for wupb ) - */ - - switch (cardSTATE) { - //case SIM_NOFIELD: - case SIM_HALTED: - case SIM_IDLE: { - LogTrace(receivedCmd, len, 0, 0, NULL, true); - break; - } - case SIM_SELECTING: { - TransmitFor14443b_AsTag( encodedATQB, encodedATQBLen ); - LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false); - cardSTATE = SIM_WORK; - break; - } - case SIM_HALTING: { - TransmitFor14443b_AsTag( encodedOK, encodedOKLen ); - LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false); - cardSTATE = SIM_HALTED; - break; - } - case SIM_ACKNOWLEDGE: { - TransmitFor14443b_AsTag( encodedOK, encodedOKLen ); - LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false); - cardSTATE = SIM_IDLE; - break; - } - case SIM_WORK: { - if ( len == 7 && receivedCmd[0] == ISO14443B_HALT ) { - cardSTATE = SIM_HALTED; - } else if ( len == 11 && receivedCmd[0] == ISO14443B_ATTRIB ) { - cardSTATE = SIM_ACKNOWLEDGE; - } else { - // Todo: - // - SLOT MARKER - // - ISO7816 - // - emulate with a memory dump - Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived); - // CRC Check - if (len >= 3){ // if crc exists - - if (!check_crc(CRC_14443_B, receivedCmd, len)) - DbpString("+++CRC fail"); - else - DbpString("CRC passes"); - } - cardSTATE = SIM_IDLE; - } - break; - } - default: break; - } - - ++cmdsReceived; - } - if (MF_DBGLEVEL >= 2) - Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, BigBuf_get_traceLen()); - switch_off(); //simulate + // prepare "OK" tag answer (encoded): + CodeIso14443bAsTag(respOK, sizeof(respOK)); + uint8_t *encodedOK = BigBuf_malloc(ToSendMax); + uint16_t encodedOKLen = ToSendMax; + memcpy(encodedOK, ToSend, ToSendMax); + + // Simulation loop + while (!BUTTON_PRESS() && !data_available()) { + WDT_HIT(); + + // find reader field + if (cardSTATE == SIM_NOFIELD) { + vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; + if (vHf > MF_MINFIELDV) { + cardSTATE = SIM_IDLE; + LED_A_ON(); + } + } + if (cardSTATE == SIM_NOFIELD) continue; + + // Get reader command + if (!GetIso14443bCommandFromReader(receivedCmd, &len)) { + Dbprintf("button pressed, received %d commands", cmdsReceived); + break; + } + + // ISO14443-B protocol states: + // REQ or WUP request in ANY state + // WUP in HALTED state + if (len == 5) { + if ((receivedCmd[0] == ISO14443B_REQB && (receivedCmd[2] & 0x8) == 0x8 && cardSTATE == SIM_HALTED) || + receivedCmd[0] == ISO14443B_REQB) { + LogTrace(receivedCmd, len, 0, 0, NULL, true); + cardSTATE = SIM_SELECTING; + } + } + + /* + * How should this flow go? + * REQB or WUPB + * send response ( waiting for Attrib) + * ATTRIB + * send response ( waiting for commands 7816) + * HALT + send halt response ( waiting for wupb ) + */ + + switch (cardSTATE) { + //case SIM_NOFIELD: + case SIM_HALTED: + case SIM_IDLE: { + LogTrace(receivedCmd, len, 0, 0, NULL, true); + break; + } + case SIM_SELECTING: { + TransmitFor14443b_AsTag(encodedATQB, encodedATQBLen); + LogTrace(respATQB, sizeof(respATQB), 0, 0, NULL, false); + cardSTATE = SIM_WORK; + break; + } + case SIM_HALTING: { + TransmitFor14443b_AsTag(encodedOK, encodedOKLen); + LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false); + cardSTATE = SIM_HALTED; + break; + } + case SIM_ACKNOWLEDGE: { + TransmitFor14443b_AsTag(encodedOK, encodedOKLen); + LogTrace(respOK, sizeof(respOK), 0, 0, NULL, false); + cardSTATE = SIM_IDLE; + break; + } + case SIM_WORK: { + if (len == 7 && receivedCmd[0] == ISO14443B_HALT) { + cardSTATE = SIM_HALTED; + } else if (len == 11 && receivedCmd[0] == ISO14443B_ATTRIB) { + cardSTATE = SIM_ACKNOWLEDGE; + } else { + // Todo: + // - SLOT MARKER + // - ISO7816 + // - emulate with a memory dump + Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsReceived); + + // CRC Check + if (len >= 3) { // if crc exists + + if (!check_crc(CRC_14443_B, receivedCmd, len)) + DbpString("+++CRC fail"); + else + DbpString("CRC passes"); + } + cardSTATE = SIM_IDLE; + } + break; + } + default: + break; + } + + ++cmdsReceived; + } + if (DBGLEVEL >= 2) + Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen()); + switch_off(); //simulate } //============================================================================= @@ -736,202 +738,202 @@ void SimulateIso14443bTag(uint32_t pupi) { * */ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { - int v = 0, myI = ABS(ci), myQ = ABS(cq); + int v = 0, myI = ABS(ci), myQ = ABS(cq); // 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; \ - } \ - } + if (Demod.sumI > 0) { \ + v = ci; \ + } else { \ + v = -ci; \ + } \ + if (Demod.sumQ > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq) // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) #define CHECK_FOR_SUBCARRIER_old() { \ - if (ci < 0) { \ - if (cq < 0) { /* ci < 0, cq < 0 */ \ - if (cq < ci) { \ - v = -cq - (ci >> 1); \ - } else { \ - v = -ci - (cq >> 1); \ - } \ - } else { /* ci < 0, cq >= 0 */ \ - if (cq < -ci) { \ - v = -ci + (cq >> 1); \ - } else { \ - v = cq - (ci >> 1); \ - } \ - } \ - } else { \ - if (cq < 0) { /* ci >= 0, cq < 0 */ \ - if (-cq < ci) { \ - v = ci - (cq >> 1); \ - } else { \ - v = -cq + (ci >> 1); \ - } \ - } else { /* ci >= 0, cq >= 0 */ \ - if (cq < ci) { \ - v = ci + (cq >> 1); \ - } else { \ - v = cq + (ci >> 1); \ - } \ - } \ - } \ - } + if (ci < 0) { \ + if (cq < 0) { /* ci < 0, cq < 0 */ \ + if (cq < ci) { \ + v = -cq - (ci >> 1); \ + } else { \ + v = -ci - (cq >> 1); \ + } \ + } else { /* ci < 0, cq >= 0 */ \ + if (cq < -ci) { \ + v = -ci + (cq >> 1); \ + } else { \ + v = cq - (ci >> 1); \ + } \ + } \ + } else { \ + if (cq < 0) { /* ci >= 0, cq < 0 */ \ + if (-cq < ci) { \ + v = ci - (cq >> 1); \ + } else { \ + v = -cq + (ci >> 1); \ + } \ + } else { /* ci >= 0, cq >= 0 */ \ + if (cq < ci) { \ + v = ci + (cq >> 1); \ + } else { \ + v = cq + (ci >> 1); \ + } \ + } \ + } \ + } //note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow #define CHECK_FOR_SUBCARRIER() { v = MAX(myI, myQ) + (MIN(myI, myQ) >> 1); } - switch(Demod.state) { - case DEMOD_UNSYNCD: + switch (Demod.state) { + case DEMOD_UNSYNCD: - CHECK_FOR_SUBCARRIER(); - - // subcarrier detected - - if (v > SUBCARRIER_DETECT_THRESHOLD) { - Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = ci; - Demod.sumQ = cq; - Demod.posCount = 1; - } - break; + CHECK_FOR_SUBCARRIER(); - case DEMOD_PHASE_REF_TRAINING: - if (Demod.posCount < 8) { + // subcarrier detected - CHECK_FOR_SUBCARRIER(); - - if (v > 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; + if (v > SUBCARRIER_DETECT_THRESHOLD) { + Demod.state = DEMOD_PHASE_REF_TRAINING; + Demod.sumI = ci; + Demod.sumQ = cq; + Demod.posCount = 1; + } + 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 { - // maximum length of TR1 = 200 1/fs - if (Demod.posCount > 200/4) Demod.state = DEMOD_UNSYNCD; - } - Demod.posCount++; - break; + case DEMOD_PHASE_REF_TRAINING: + if (Demod.posCount < 8) { - case DEMOD_GOT_FALLING_EDGE_OF_SOF: - Demod.posCount++; - - MAKE_SOFT_DECISION(); - - if (v > 0) { - // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges - if (Demod.posCount < 9*2) { - Demod.state = DEMOD_UNSYNCD; - } else { - LED_C_ON(); // Got SOF - Demod.state = DEMOD_AWAITING_START_BIT; - Demod.posCount = 0; - Demod.len = 0; - } - } else { - // low phase of SOF too long (> 12 etu) - if (Demod.posCount > 14*2) { - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - } - } - break; + CHECK_FOR_SUBCARRIER(); - case DEMOD_AWAITING_START_BIT: - Demod.posCount++; - - MAKE_SOFT_DECISION(); - - if (v > 0) { - if (Demod.posCount > 6*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - } - } else { // start bit detected - Demod.bitCount = 0; - Demod.posCount = 1; // this was the first half - Demod.thisBit = v; - Demod.shiftReg = 0; - Demod.state = DEMOD_RECEIVING_DATA; - } - break; + if (v > 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_RECEIVING_DATA: - - MAKE_SOFT_DECISION(); + case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: - if (Demod.posCount == 0) { - // first half of bit - Demod.thisBit = v; - Demod.posCount = 1; - } else { - // second half of bit - Demod.thisBit += v; - Demod.shiftReg >>= 1; + MAKE_SOFT_DECISION(); - // OR in a logic '1' - if (Demod.thisBit > 0) - Demod.shiftReg |= 0x200; + if (v < 0) { // logic '0' detected + Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; + Demod.posCount = 0; // start of SOF sequence + } else { + // maximum length of TR1 = 200 1/fs + if (Demod.posCount > 200 / 4) Demod.state = DEMOD_UNSYNCD; + } + Demod.posCount++; + break; - Demod.bitCount++; - - // 1 start 8 data 1 stop = 10 - if (Demod.bitCount == 10) { - - uint16_t s = Demod.shiftReg; - - // stop bit == '1', start bit == '0' - if ((s & 0x200) && (s & 0x001) == 0 ) { - // left shift to drop the startbit - uint8_t b = (s >> 1); - Demod.output[Demod.len] = b; - ++Demod.len; - Demod.state = DEMOD_AWAITING_START_BIT; - } else { - // this one is a bit hard, either its a correc byte or its unsynced. - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - - // This is EOF (start, stop and all data bits == '0' - if (s == 0) return true; - } - } - Demod.posCount = 0; - } - break; + case DEMOD_GOT_FALLING_EDGE_OF_SOF: + Demod.posCount++; - default: - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - break; - } - return false; + MAKE_SOFT_DECISION(); + + if (v > 0) { + // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges + if (Demod.posCount < 9 * 2) { + Demod.state = DEMOD_UNSYNCD; + } else { + LED_C_ON(); // Got SOF + Demod.state = DEMOD_AWAITING_START_BIT; + Demod.posCount = 0; + Demod.len = 0; + } + } else { + // low phase of SOF too long (> 12 etu) + if (Demod.posCount > 14 * 2) { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } + break; + + case DEMOD_AWAITING_START_BIT: + Demod.posCount++; + + MAKE_SOFT_DECISION(); + + if (v > 0) { + if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } else { // start bit detected + Demod.bitCount = 0; + 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; + Demod.shiftReg >>= 1; + + // OR in a logic '1' + if (Demod.thisBit > 0) + Demod.shiftReg |= 0x200; + + Demod.bitCount++; + + // 1 start 8 data 1 stop = 10 + if (Demod.bitCount == 10) { + + uint16_t s = Demod.shiftReg; + + // stop bit == '1', start bit == '0' + if ((s & 0x200) && (s & 0x001) == 0) { + // left shift to drop the startbit + uint8_t b = (s >> 1); + Demod.output[Demod.len] = b; + ++Demod.len; + Demod.state = DEMOD_AWAITING_START_BIT; + } else { + // this one is a bit hard, either its a correc byte or its unsynced. + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + + // This is EOF (start, stop and all data bits == '0' + if (s == 0) return true; + } + } + Demod.posCount = 0; + } + break; + + default: + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + break; + } + return false; } @@ -940,99 +942,98 @@ static RAMFUNC int Handle14443bTagSamplesDemod(int ci, int cq) { * quiet: set to 'TRUE' to disable debug output */ static void GetTagSamplesFor14443bDemod() { - bool gotFrame = false, finished = false; - int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - int ci = 0, cq = 0; - uint32_t time_0 = 0, time_stop = 0; + bool finished = false; +// int lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + uint32_t time_0 = 0, time_stop = 0; - BigBuf_free(); - - // Set up the demodulator for tag -> reader responses. - DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - - // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); - int8_t *upTo = dmaBuf; - - // Setup and start DMA. - if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE) ){ - if (MF_DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); - return; - } + BigBuf_free(); - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + // Set up the demodulator for tag -> reader responses. + DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - // get current clock - time_0 = GetCountSspClk(); - - // rx counter - dma counter? (how much?) & (mod) mask > 2. (since 2bytes at the time is read) - while ( !finished ) { + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = (int8_t *) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + int8_t *upTo = dmaBuf; - LED_A_INV(); - WDT_HIT(); + // Setup and start DMA. + if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting"); + return; + } - // LSB is a fpga signal bit. - ci = upTo[0]; - cq = upTo[1]; - upTo += 2; - lastRxCounter -= 2; + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); - // restart DMA buffer to receive again. - if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { - upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; - } + // get current clock + time_0 = GetCountSspClk(); - // https://github.com/Proxmark/proxmark3/issues/103 - gotFrame = Handle14443bTagSamplesDemod(ci, cq); - time_stop = GetCountSspClk() - time_0; + // rx counter - dma counter? (how much?) & (mod) mask > 2. (since 2bytes at the time is read) + while (!finished) { - finished = (time_stop > iso14b_timeout || gotFrame); - } - - FpgaDisableSscDma(); - - if ( upTo ) - upTo = NULL; - - if ( Demod.len > 0 ) - LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); + LED_A_INV(); + WDT_HIT(); + + // LSB is a fpga signal bit. + int ci = upTo[0]; + int cq = upTo[1]; + upTo += 2; +// lastRxCounter -= 2; + + // restart DMA buffer to receive again. + if (upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + upTo = dmaBuf; +// lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + } + + // https://github.com/Proxmark/proxmark3/issues/103 + bool gotFrame = Handle14443bTagSamplesDemod(ci, cq); + time_stop = GetCountSspClk() - time_0; + + finished = (time_stop > iso14b_timeout || gotFrame); + } + + FpgaDisableSscDma(); + + if (upTo) + upTo = NULL; + + if (Demod.len > 0) + LogTrace(Demod.output, Demod.len, time_0, time_stop, NULL, false); } //----------------------------------------------------------------------------- // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- static void TransmitFor14443b_AsReader(void) { - int c; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); - SpinDelay(60); - - // What does this loop do? Is it TR1? - // 0xFF = 8 bits of 1. 1 bit == 1Etu,.. - // loop 10 * 8 = 80 ETU of delay, with a non modulated signal. why? - // 80*9 = 720us. + int c; - for(c = 0; c < 50;) { - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xFF; - c++; - } - } - - // Send frame loop - for(c = 0; c < ToSendMax;) { - - // Put byte into tx holding register as soon as it is ready - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c++]; - } - } - WDT_HIT(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + SpinDelay(60); + + // What does this loop do? Is it TR1? + // 0xFF = 8 bits of 1. 1 bit == 1Etu,.. + // loop 10 * 8 = 80 ETU of delay, with a non modulated signal. why? + // 80*9 = 720us. + + for (c = 0; c < 50;) { + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xFF; + c++; + } + } + + // Send frame loop + for (c = 0; c < ToSendMax;) { + + // Put byte into tx holding register as soon as it is ready + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c++]; + } + } + WDT_HIT(); } //----------------------------------------------------------------------------- @@ -1040,81 +1041,79 @@ static void TransmitFor14443b_AsReader(void) { // so that it is ready to transmit to the tag using TransmitFor14443b(). //----------------------------------------------------------------------------- static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { - /* - * Reader data transmission: - * - no modulation ONES - * - SOF - * - Command, data and CRC_B - * - EOF - * - no modulation ONES - * - * 1 ETU == 1 BIT! - * TR0 - 8 ETUS minimum. - * - * QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode? - * 1 "stuffbit" = 1ETU (9us) - */ - int i; - uint8_t b; - - ToSendReset(); + /* + * Reader data transmission: + * - no modulation ONES + * - SOF + * - Command, data and CRC_B + * - EOF + * - no modulation ONES + * + * 1 ETU == 1 BIT! + * TR0 - 8 ETUS minimum. + * + * QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode? + * 1 "stuffbit" = 1ETU (9us) + */ - // Send SOF - // 10-11 ETUs of ZERO - for(i = 0; i < 10; ++i) ToSendStuffBit(0); - - // 2-3 ETUs of ONE - ToSendStuffBit(1); - ToSendStuffBit(1); -// ToSendStuffBit(1); - - // Sending cmd, LSB - // from here we add BITS - for(i = 0; i < len; ++i) { - // Start bit - ToSendStuffBit(0); - // Data bits - b = cmd[i]; - // if ( b & 1 ) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>1) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>2) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>3) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>4) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>5) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>6) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); - // if ( (b>>7) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + ToSendReset(); - ToSendStuffBit( b & 1); - ToSendStuffBit( (b>>1) & 1); - ToSendStuffBit( (b>>2) & 1); - ToSendStuffBit( (b>>3) & 1); - ToSendStuffBit( (b>>4) & 1); - ToSendStuffBit( (b>>5) & 1); - ToSendStuffBit( (b>>6) & 1); - ToSendStuffBit( (b>>7) & 1); - - // Stop bit - ToSendStuffBit(1); - // EGT extra guard time - // For PCD it ranges 0-57us (1etu = 9us) - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Send EOF - // 10-11 ETUs of ZERO - for(i = 0; i < 10; ++i) ToSendStuffBit(0); + // Send SOF + // 10-11 ETUs of ZERO + for (int i = 0; i < 10; ++i) ToSendStuffBit(0); - // Transition time. TR0 - guard time - // 8ETUS minum? - // Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF. - // I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode - for(i = 0; i < 24 ; ++i) ToSendStuffBit(1); - - // TR1 - Synchronization time - // Convert from last character reference to length - ToSendMax++; + // 2-3 ETUs of ONE + ToSendStuffBit(1); + ToSendStuffBit(1); +// ToSendStuffBit(1); + + // Sending cmd, LSB + // from here we add BITS + for (int i = 0; i < len; ++i) { + // Start bit + ToSendStuffBit(0); + // Data bits + uint8_t b = cmd[i]; + // if ( b & 1 ) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>1) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>2) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>3) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>4) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>5) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>6) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + // if ( (b>>7) & 1) ToSendStuffBit(1); else ToSendStuffBit(0); + + ToSendStuffBit(b & 1); + ToSendStuffBit((b >> 1) & 1); + ToSendStuffBit((b >> 2) & 1); + ToSendStuffBit((b >> 3) & 1); + ToSendStuffBit((b >> 4) & 1); + ToSendStuffBit((b >> 5) & 1); + ToSendStuffBit((b >> 6) & 1); + ToSendStuffBit((b >> 7) & 1); + + // Stop bit + ToSendStuffBit(1); + // EGT extra guard time + // For PCD it ranges 0-57us (1etu = 9us) + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Send EOF + // 10-11 ETUs of ZERO + for (int i = 0; i < 10; ++i) ToSendStuffBit(0); + + // Transition time. TR0 - guard time + // 8ETUS minum? + // Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF. + // I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode + for (int i = 0; i < 24 ; ++i) ToSendStuffBit(1); + + // TR1 - Synchronization time + // Convert from last character reference to length + ToSendMax++; } /* @@ -1122,15 +1121,15 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { */ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { - uint32_t time_start = GetCountSspClk(); - - CodeIso14443bAsReader(cmd, len); + uint32_t time_start = GetCountSspClk(); - TransmitFor14443b_AsReader(); + CodeIso14443bAsReader(cmd, len); - if(trigger) LED_A_ON(); + TransmitFor14443b_AsReader(); - LogTrace(cmd, len, time_start, GetCountSspClk()-time_start, NULL, true); + if (trigger) LED_A_ON(); + + LogTrace(cmd, len, time_start, GetCountSspClk() - time_start, NULL, true); } /* Sends an APDU to the tag @@ -1138,91 +1137,91 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { */ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { - 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) - AddCrc14B(message_frame, message_length + 2); - // send - CodeAndTransmit14443bAsReader(message_frame, message_length + 4); //no - // get response - GetTagSamplesFor14443bDemod(); //no - if(Demod.len < 3) - return 0; - - // VALIDATE CRC - if (!check_crc(CRC_14443_B, Demod.output, Demod.len)){ - if (MF_DBGLEVEL > 3) Dbprintf("crc fail ICE"); - return 0; - } - // copy response contents - if(response != NULL) - memcpy(response, Demod.output, Demod.len); + 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) + AddCrc14B(message_frame, message_length + 2); + // send + CodeAndTransmit14443bAsReader(message_frame, message_length + 4); //no + // get response + GetTagSamplesFor14443bDemod(); //no + if (Demod.len < 3) + return 0; - return Demod.len; + // VALIDATE CRC + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { + if (DBGLEVEL > 3) Dbprintf("crc fail ICE"); + return 0; + } + // copy response contents + if (response != NULL) + memcpy(response, Demod.output, Demod.len); + + return Demod.len; } /** * SRx Initialise. */ -uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card ) { - // INITIATE command: wake up the tag using the INITIATE - static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b }; - // SELECT command (with space for CRC) - uint8_t select_srx[] = { ISO14443B_SELECT, 0x00, 0x00, 0x00}; - - CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx)); - GetTagSamplesFor14443bDemod(); //no +uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { + // INITIATE command: wake up the tag using the INITIATE + static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b }; + // SELECT command (with space for CRC) + uint8_t select_srx[] = { ISO14443B_SELECT, 0x00, 0x00, 0x00}; - if (Demod.len == 0) - return 2; + CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx)); + GetTagSamplesFor14443bDemod(); //no - // Randomly generated Chip ID - if (card) card->chipid = Demod.output[0]; - - select_srx[1] = Demod.output[0]; - - AddCrc14B(select_srx, 2); - - CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx)); - GetTagSamplesFor14443bDemod(); //no - - if (Demod.len != 3) - return 2; - - // Check the CRC of the answer: - if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) - return 3; - - // Check response from the tag: should be the same UID as the command we just sent: - if (select_srx[1] != Demod.output[0]) - return 1; + if (Demod.len == 0) + return 2; - // First get the tag's UID: - select_srx[0] = ISO14443B_GET_UID; + // Randomly generated Chip ID + if (card) card->chipid = Demod.output[0]; - AddCrc14B(select_srx, 1); - CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one - GetTagSamplesFor14443bDemod(); //no + select_srx[1] = Demod.output[0]; - if (Demod.len != 10) - return 2; - - // The check the CRC of the answer - if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) - return 3; + AddCrc14B(select_srx, 2); - if (card) { - card->uidlen = 8; - memcpy(card->uid, Demod.output, 8); - } + CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx)); + GetTagSamplesFor14443bDemod(); //no - return 0; + if (Demod.len != 3) + return 2; + + // Check the CRC of the answer: + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) + return 3; + + // Check response from the tag: should be the same UID as the command we just sent: + if (select_srx[1] != Demod.output[0]) + return 1; + + // First get the tag's UID: + select_srx[0] = ISO14443B_GET_UID; + + AddCrc14B(select_srx, 1); + CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one + GetTagSamplesFor14443bDemod(); //no + + if (Demod.len != 10) + return 2; + + // The check the CRC of the answer + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) + return 3; + + if (card) { + card->uidlen = 8; + memcpy(card->uid, Demod.output, 8); + } + + return 0; } /* Perform the ISO 14443 B Card Selection procedure * Currently does NOT do any collision handling. @@ -1230,34 +1229,34 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card ) { * TODO: Support multiple cards (perform anticollision) * TODO: Verify CRC checksums */ -uint8_t iso14443b_select_card(iso14b_card_select_t *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[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; - // ATTRIB command (with space for CRC) - uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; - - // first, wake up the tag - CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); - GetTagSamplesFor14443bDemod(); //select_card - - // ATQB too short? - if (Demod.len < 14) - return 2; - - // VALIDATE CRC - if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) - return 3; - - if (card) { - card->uidlen = 4; - memcpy(card->uid, Demod.output+1, 4); - memcpy(card->atqb, Demod.output+5, 7); - } +uint8_t iso14443b_select_card(iso14b_card_select_t *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[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; + // ATTRIB command (with space for CRC) + uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; + + // first, wake up the tag + CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); + GetTagSamplesFor14443bDemod(); //select_card + + // ATQB too short? + if (Demod.len < 14) + return 2; + + // VALIDATE CRC + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) + return 3; + + if (card) { + card->uidlen = 4; + memcpy(card->uid, Demod.output + 1, 4); + memcpy(card->atqb, Demod.output + 5, 7); + } // copy the PUPI to ATTRIB ( PUPI == UID ) 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; AddCrc14B(attrib, 9); @@ -1266,64 +1265,64 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card ) { GetTagSamplesFor14443bDemod();//select_card // Answer to ATTRIB too short? - if(Demod.len < 3) - return 2; + if (Demod.len < 3) + return 2; - // VALIDATE CRC - if (!check_crc(CRC_14443_B, Demod.output, Demod.len) ) - return 3; + // VALIDATE CRC + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) + return 3; - if (card) { - - // CID - card->cid = Demod.output[0]; + if (card) { - // MAX FRAME - uint16_t maxFrame = card->atqb[5] >> 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; - iso14b_set_maxframesize(maxFrame); - - // FWT - uint8_t fwt = card->atqb[6] >> 4; - if ( fwt < 16 ){ - uint32_t fwt_time = (302 << fwt); - iso14b_set_timeout( fwt_time); - } - } - // reset PCB block number - pcb_blocknum = 0; - return 0; + // CID + card->cid = Demod.output[0]; + + // MAX FRAME + uint16_t maxFrame = card->atqb[5] >> 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; + iso14b_set_maxframesize(maxFrame); + + // FWT + uint8_t fwt = card->atqb[6] >> 4; + if (fwt < 16) { + uint32_t fwt_time = (302 << fwt); + iso14b_set_timeout(fwt_time); + } + } + // reset PCB block number + pcb_blocknum = 0; + return 0; } // Set up ISO 14443 Type B communication (similar to iso14443a_setup) // field is setup for "Sending as Reader" void iso14443b_setup() { - LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - // Initialize Demod and Uart structs - DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); + LEDsoff(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // Initialize Demod and Uart structs + DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); + UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); - // Set up the synchronous serial port - FpgaSetupSsc(); - - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); - SpinDelay(100); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Start the timer - StartCountSspClk(); - - LED_D_ON(); + // Set up the synchronous serial port + FpgaSetupSsc(); + + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + SpinDelay(100); + + // Start the timer + StartCountSspClk(); + + LED_D_ON(); } //----------------------------------------------------------------------------- @@ -1336,106 +1335,106 @@ void iso14443b_setup() { // I tried to be systematic and check every answer of the tag, every CRC, etc... //----------------------------------------------------------------------------- static bool ReadSTBlock(uint8_t block) { - uint8_t cmd[] = {ISO14443B_READ_BLK, block, 0x00, 0x00}; - AddCrc14B(cmd, 2); - CodeAndTransmit14443bAsReader(cmd, sizeof(cmd)); - GetTagSamplesFor14443bDemod(); + uint8_t cmd[] = {ISO14443B_READ_BLK, block, 0x00, 0x00}; + AddCrc14B(cmd, 2); + CodeAndTransmit14443bAsReader(cmd, sizeof(cmd)); + GetTagSamplesFor14443bDemod(); - // Check if we got an answer from the tag - if (Demod.len != 6) { - DbpString("[!] expected 6 bytes from tag, got less..."); - return false; - } - // The check the CRC of the answer - if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { - DbpString("[!] CRC Error block!"); - return false; - } - return true; + // Check if we got an answer from the tag + if (Demod.len != 6) { + DbpString("[!] expected 6 bytes from tag, got less..."); + return false; + } + // The check the CRC of the answer + if (!check_crc(CRC_14443_B, Demod.output, Demod.len)) { + DbpString("[!] CRC Error block!"); + return false; + } + return true; } void ReadSTMemoryIso14443b(uint8_t numofblocks) { - // Make sure that we start from off, since the tags are stateful; - // confusing things will happen if we don't reset them between reads. - //switch_off(); - - uint8_t i = 0x00; - uint8_t *buf = BigBuf_malloc(sizeof(iso14b_card_select_t)); + // Make sure that we start from off, since the tags are stateful; + // confusing things will happen if we don't reset them between reads. + //switch_off(); - iso14443b_setup(); - - iso14b_card_select_t *card = (iso14b_card_select_t*)buf; - uint8_t res = iso14443b_select_srx_card(card); + uint8_t i = 0x00; + uint8_t *buf = BigBuf_malloc(sizeof(iso14b_card_select_t)); - // 0: OK 2: attrib fail, 3:crc fail, - if ( res > 0 ) goto out; - - Dbprintf("[+] Tag memory dump, block 0 to %d", numofblocks); + iso14443b_setup(); - ++numofblocks; - - for (;;) { - if (i == numofblocks) { - DbpString("System area block (0xFF):"); - i = 0xff; - } + iso14b_card_select_t *card = (iso14b_card_select_t *)buf; + uint8_t res = iso14443b_select_srx_card(card); - uint8_t retries = 3; - do { - res = ReadSTBlock(i); - } while (!res && --retries); - - if (!res && !retries) { - goto out; - } - - // 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]); + // 0: OK 2: attrib fail, 3:crc fail, + if (res > 0) goto out; - if (i == 0xff) break; - ++i; - } - -out: - switch_off(); // disconnect raw - SpinDelay(20); + Dbprintf("[+] Tag memory dump, block 0 to %d", numofblocks); + + ++numofblocks; + + for (;;) { + if (i == numofblocks) { + DbpString("System area block (0xFF):"); + i = 0xff; + } + + uint8_t retries = 3; + do { + res = ReadSTBlock(i); + } while (!res && --retries); + + if (!res && !retries) { + goto out; + } + + // 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; + } + +out: + switch_off(); // disconnect raw + SpinDelay(20); } -static void iso1444b_setup_sniff(void){ +static void iso1444b_setup_sniff(void) { - LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - BigBuf_free(); - BigBuf_Clear_ext(false); - clear_trace();//setup snoop - set_tracing(true); + LEDsoff(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); - // Initialize Demod and Uart structs - DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); + // Initialize Demod and Uart structs + DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); + UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); - if (MF_DBGLEVEL > 1) { - // Print debug information about the buffer sizes - Dbprintf("[+] Sniff 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); - } + if (DBGLEVEL > 1) { + // Print debug information about the buffer sizes + Dbprintf("[+] Sniff 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); + } - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // connect Demodulated Signal to ADC: + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Setup for the DMA. - FpgaSetupSsc(); + // Setup for the DMA. + FpgaSetupSsc(); - // Set FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); - SpinDelay(20); + // Set FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + SpinDelay(20); - // Start the SSP timer - StartCountSspClk(); + // Start the SSP timer + StartCountSspClk(); } //============================================================================= @@ -1457,98 +1456,97 @@ static void iso1444b_setup_sniff(void){ */ void RAMFUNC SniffIso14443b(void) { - uint32_t time_0 = 0, time_start = 0, time_stop = 0; - int ci = 0, cq = 0; + uint32_t time_0 = 0, time_start = 0, time_stop; - // 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. - 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 + // response from the tag. + bool TagIsActive = false; + bool ReaderIsActive = false; - iso1444b_setup_sniff(); - - // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); - int8_t *data = dmaBuf; + iso1444b_setup_sniff(); - // Setup and start DMA. - if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE) ){ - if (MF_DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting"); - BigBuf_free(); - return; - } + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = (int8_t *) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + int8_t *data = dmaBuf; + + // Setup and start DMA. + if (!FpgaSetupSscDma((uint8_t *) dmaBuf, ISO14443B_DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting"); + BigBuf_free(); + return; + } + + // time ZERO, the point from which it all is calculated. + time_0 = GetCountSspClk(); - // time ZERO, the point from which it all is calculated. - time_0 = GetCountSspClk(); - // loop and listen - while (!BUTTON_PRESS()) { - WDT_HIT(); + while (!BUTTON_PRESS()) { + WDT_HIT(); - ci = data[0]; - cq = data[1]; - data += 2; - - if (data >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { - data = dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; - } + int ci = data[0]; + int cq = data[1]; + data += 2; - // no need to try decoding reader data if the tag is sending - if (!TagIsActive) { - - LED_A_INV(); - - if (Handle14443bReaderUartBit(ci & 0x01)) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, NULL, true); - UartReset(); - DemodReset(); - } else { - time_start = GetCountSspClk() - time_0; - } - - if (Handle14443bReaderUartBit(cq & 0x01)) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, NULL, true); - UartReset(); - DemodReset(); - } else { - time_start = GetCountSspClk() - time_0; - } - ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); - } - - // no need to try decoding tag data if the reader is sending - and we cannot afford the time - if (!ReaderIsActive) { + if (data >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + data = dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + } - // is this | 0x01 the error? & 0xfe in https://github.com/Proxmark/proxmark3/issues/103 - // LSB is a fpga signal bit. - if (Handle14443bTagSamplesDemod(ci, cq)) { - time_stop = GetCountSspClk() - time_0; - LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); - UartReset(); - DemodReset(); - } else { - time_start = GetCountSspClk() - time_0; - } - TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF); - } - } - - if (MF_DBGLEVEL >= 2) { - DbpString("[+] Sniff statistics:"); - Dbprintf("[+] uart State: %x ByteCount: %i ByteCountMax: %i", Uart.state, Uart.byteCnt, Uart.byteCntMax); - Dbprintf("[+] trace length: %i", BigBuf_get_traceLen()); - } - - switch_off(); + // no need to try decoding reader data if the tag is sending + if (!TagIsActive) { + + LED_A_INV(); + + if (Handle14443bReaderUartBit(ci & 0x01)) { + time_stop = GetCountSspClk() - time_0; + LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, NULL, true); + UartReset(); + DemodReset(); + } else { + time_start = GetCountSspClk() - time_0; + } + + if (Handle14443bReaderUartBit(cq & 0x01)) { + time_stop = GetCountSspClk() - time_0; + LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, NULL, true); + UartReset(); + DemodReset(); + } else { + time_start = GetCountSspClk() - time_0; + } + ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); + } + + // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { + + // is this | 0x01 the error? & 0xfe in https://github.com/Proxmark/proxmark3/issues/103 + // LSB is a fpga signal bit. + if (Handle14443bTagSamplesDemod(ci, cq)) { + time_stop = GetCountSspClk() - time_0; + LogTrace(Demod.output, Demod.len, time_start, time_stop, NULL, false); + UartReset(); + DemodReset(); + } else { + time_start = GetCountSspClk() - time_0; + } + TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF); + } + } + + if (DBGLEVEL >= 2) { + DbpString("[+] Sniff statistics:"); + Dbprintf("[+] uart State: %x ByteCount: %i ByteCountMax: %i", Uart.state, Uart.byteCnt, Uart.byteCntMax); + Dbprintf("[+] trace length: %i", BigBuf_get_traceLen()); + } + + switch_off(); } void iso14b_set_trigger(bool enable) { - trigger = enable; + trigger = enable; } /* @@ -1562,71 +1560,75 @@ void iso14b_set_trigger(bool enable) { * none * */ -void SendRawCommand14443B_Ex(UsbCommand *c) { - iso14b_command_t param = c->arg[0]; - size_t len = c->arg[1] & 0xffff; - uint8_t *cmd = c->d.asBytes; - uint8_t status = 0; - uint32_t sendlen = sizeof(iso14b_card_select_t); - uint8_t buf[USB_CMD_DATA_SIZE] = {0x00}; +void SendRawCommand14443B_Ex(PacketCommandNG *c) { + iso14b_command_t param = c->oldarg[0]; + size_t len = c->oldarg[1] & 0xffff; + uint32_t timeout = c->oldarg[2]; + uint8_t *cmd = c->data.asBytes; + uint8_t status; + uint32_t sendlen = sizeof(iso14b_card_select_t); + uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; - if (MF_DBGLEVEL > 3) Dbprintf("14b raw: param, %04x", param ); - - // turn on trigger (LED_A) - if ((param & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) - iso14b_set_trigger(true); - - if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) { - iso14443b_setup(); - clear_trace(); - } - - set_tracing(true); + if (DBGLEVEL > 3) Dbprintf("14b raw: param, %04x", param); - if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { - iso14b_card_select_t *card = (iso14b_card_select_t*)buf; - status = iso14443b_select_card(card); - cmd_send(CMD_ACK, status, sendlen, 0, buf, sendlen); - // 0: OK 2: attrib fail, 3:crc fail, - if ( status > 0 ) goto out; - } - - if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { - iso14b_card_select_t *card = (iso14b_card_select_t*)buf; - status = iso14443b_select_srx_card(card); - cmd_send(CMD_ACK, status, sendlen, 0, buf, sendlen); - // 0: OK 2: demod fail, 3:crc fail, - if ( status > 0 ) goto out; - } - - if ((param & ISO14B_APDU) == ISO14B_APDU) { - status = iso14443b_apdu(cmd, len, buf); - cmd_send(CMD_ACK, status, status, 0, buf, status); - } - - if ((param & ISO14B_RAW) == ISO14B_RAW) { - if((param & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) { - AddCrc14B(cmd, len); - len += 2; - } - - CodeAndTransmit14443bAsReader(cmd, len); // raw - GetTagSamplesFor14443bDemod(); // raw - - sendlen = MIN(Demod.len, USB_CMD_DATA_SIZE); - status = (Demod.len > 0) ? 0 : 1; - cmd_send(CMD_ACK, status, sendlen, 0, Demod.output, sendlen); - } - -out: - // turn off trigger (LED_A) - if ((param & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) - iso14b_set_trigger(false); + // turn on trigger (LED_A) + if ((param & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) + iso14b_set_trigger(true); - // turn off antenna et al - // we don't send a HALT command. - if ((param & ISO14B_DISCONNECT) == ISO14B_DISCONNECT) { - switch_off(); // disconnect raw - SpinDelay(20); - } -} \ No newline at end of file + if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) { + iso14443b_setup(); + clear_trace(); + } + + if ((param & ISO14B_SET_TIMEOUT)) + iso14b_set_timeout(timeout); + + set_tracing(true); + + if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { + iso14b_card_select_t *card = (iso14b_card_select_t *)buf; + status = iso14443b_select_card(card); + reply_old(CMD_ACK, status, sendlen, 0, buf, sendlen); + // 0: OK 2: attrib fail, 3:crc fail, + if (status > 0) goto out; + } + + if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { + iso14b_card_select_t *card = (iso14b_card_select_t *)buf; + status = iso14443b_select_srx_card(card); + reply_old(CMD_ACK, status, sendlen, 0, buf, sendlen); + // 0: OK 2: demod fail, 3:crc fail, + if (status > 0) goto out; + } + + if ((param & ISO14B_APDU) == ISO14B_APDU) { + status = iso14443b_apdu(cmd, len, buf); + reply_old(CMD_ACK, status, status, 0, buf, status); + } + + if ((param & ISO14B_RAW) == ISO14B_RAW) { + if ((param & ISO14B_APPEND_CRC) == ISO14B_APPEND_CRC) { + AddCrc14B(cmd, len); + len += 2; + } + + CodeAndTransmit14443bAsReader(cmd, len); // raw + GetTagSamplesFor14443bDemod(); // raw + + sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); + status = (Demod.len > 0) ? 0 : 1; + reply_old(CMD_ACK, status, sendlen, 0, Demod.output, sendlen); + } + +out: + // turn off trigger (LED_A) + if ((param & ISO14B_REQUEST_TRIGGER) == ISO14B_REQUEST_TRIGGER) + iso14b_set_trigger(false); + + // turn off antenna et al + // we don't send a HALT command. + if ((param & ISO14B_DISCONNECT) == ISO14B_DISCONNECT) { + switch_off(); // disconnect raw + SpinDelay(20); + } +} diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 84765537a..5ea3d530b 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -18,7 +18,7 @@ extern "C" { #endif #include "proxmark3.h" -#include "common.h" // access to global variable: MF_DBGLEVEL +#include "common.h" // access to global variable: DBGLEVEL #include "apps.h" #include "util.h" #include "string.h" @@ -27,31 +27,31 @@ extern "C" { #include "protocols.h" #ifndef AddCrc14A -# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) +# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1) #endif #ifndef AddCrc14B -# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1) +# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1) #endif -extern void SendRawCommand14443B_Ex(UsbCommand *c); -extern void iso14443b_setup(); -extern uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); -extern uint8_t iso14443b_select_card(iso14b_card_select_t* card); -extern uint8_t iso14443b_select_card_srx(iso14b_card_select_t* card); +void SendRawCommand14443B_Ex(PacketCommandNG *c); +void iso14443b_setup(); +uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); +uint8_t iso14443b_select_card(iso14b_card_select_t *card); +uint8_t iso14443b_select_card_srx(iso14b_card_select_t *card); // testfunctions -extern void WaitForFpgaDelayQueueIsEmpty( uint16_t delay ); -extern void ClearFpgaShiftingRegisters(void); +void WaitForFpgaDelayQueueIsEmpty(uint16_t delay); +void ClearFpgaShiftingRegisters(void); // States for 14B SIM command -#define SIM_NOFIELD 0 -#define SIM_IDLE 1 -#define SIM_HALTED 2 -#define SIM_SELECTING 3 -#define SIM_HALTING 4 +#define SIM_NOFIELD 0 +#define SIM_IDLE 1 +#define SIM_HALTED 2 +#define SIM_SELECTING 3 +#define SIM_HALTING 4 #define SIM_ACKNOWLEDGE 5 -#define SIM_WORK 6 +#define SIM_WORK 6 #ifdef __cplusplus } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 285ac226d..374b2be23 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -14,31 +14,31 @@ // 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 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 +// 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 +// 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 @@ -49,13 +49,13 @@ // TODO / BUGS / ISSUES: // *) 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 from the card is still a bit shaky. // *) signal decoding is unable to detect collissions. -// *) add anti-collission support for inventory-commands +// *) add anti-collission support for inventory-commands // *) read security status of a block -// *) sniffing and simulation do only support one transmission mode. need to support -// all 8 transmission combinations -// *) remove or refactor code under "depricated" +// *) 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 "proxmark3.h" @@ -70,29 +70,29 @@ // This section basicly contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -// 32 + 2 crc + 1 -#define ISO15_MAX_FRAME 35 -#define CMD_ID_RESP 5 -#define CMD_READ_RESP 13 -#define CMD_INV_RESP 12 +// 32 + 2 crc + 1 +#define ISO15_MAX_FRAME 35 +#define CMD_ID_RESP 5 +#define CMD_READ_RESP 13 +#define CMD_INV_RESP 12 #define FrameSOF Iso15693FrameSOF #define Logic0 Iso15693Logic0 #define Logic1 Iso15693Logic1 #define FrameEOF Iso15693FrameEOF -#define Crc(data, len) crc(CRC_15693, (data), (len)) -#define CheckCrc(data, len) check_crc(CRC_15693, (data), (len)) -#define AddCrc(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +//#define Crc(data, len) Crc(CRC_15693, (data), (len)) +#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) +#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) -#define sprintUID(target,uid) Iso15693sprintUID((target), (uid)) +#define sprintUID(target,uid) Iso15693sprintUID((target), (uid)) static void BuildIdentifyRequest(uint8_t *cmdout); //static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber ); static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid); // --------------------------- -// Signal Processing +// Signal Processing // --------------------------- // prepare data using "1 out of 4" code for later transmission @@ -100,156 +100,156 @@ static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid); // cmd ... data // n ... length of data static void CodeIso15693AsReader(uint8_t *cmd, int n) { - int i, j; + int i, j; - ToSendReset(); + ToSendReset(); - // Give it a bit of slack at the beginning - for(i = 0; i < 24; i++) - ToSendStuffBit(1); + // Give it a bit of slack at the beginning + for (i = 0; i < 24; i++) + ToSendStuffBit(1); - // 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: - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 1: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 2: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - break; - case 3: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - break; - } - } - } - // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); + // 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: + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 1: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 2: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + break; + case 3: + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + break; + } + } + } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); - // And slack at the end, too. - for(i = 0; i < 24; i++) - ToSendStuffBit(1); + // And slack at the end, too. + for (i = 0; i < 24; i++) + ToSendStuffBit(1); } // encode data using "1 out of 256" sheme -// data rate is 1,66 kbit/s (fc/8192) +// 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; + int i, j; - ToSendReset(); + ToSendReset(); - // Give it a bit of slack at the beginning - for(i = 0; i < 24; i++) - ToSendStuffBit(1); + // Give it a bit of slack at the beginning + for (i = 0; i < 24; i++) + ToSendStuffBit(1); - // SOF for 1of256 - 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(1); - ToSendStuffBit(1); - } - } - } - // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); + // SOF for 1of256 + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); - // And slack at the end, too. - for(i = 0; i < 24; i++) - ToSendStuffBit(1); + for (i = 0; i < n; i++) { + for (j = 0; j <= 255; j++) { + if (cmd[i] == j) { + ToSendStuffBit(1); + ToSendStuffBit(0); + } else { + ToSendStuffBit(1); + ToSendStuffBit(1); + } + } + } + // EOF + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + + // And slack at the end, too. + for (i = 0; i < 24; i++) + ToSendStuffBit(1); } // 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; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - if (wait) { - for (c = 0; c < *wait;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - ++c; - } - WDT_HIT(); - } - } + if (wait) { + for (c = 0; c < *wait;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! + ++c; + } + WDT_HIT(); + } + } 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]; - if( ++c >= len) break; + if (++c >= len) break; } - WDT_HIT(); + WDT_HIT(); + } + + if (samples) { + if (wait) + *samples = (c + *wait) << 3; + else + *samples = c << 3; } - - if (samples) { - if (wait) - *samples = (c + *wait) << 3; - else - *samples = c << 3; - } } //----------------------------------------------------------------------------- @@ -257,179 +257,179 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *w //----------------------------------------------------------------------------- static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) { int c = 0; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - - if (wait) { - for (c = 0; c < *wait;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - ++c; - } - WDT_HIT(); - } - } + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c]; - if( ++c >= len) break; + if (wait) { + for (c = 0; c < *wait;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! + ++c; + } + WDT_HIT(); } - WDT_HIT(); } - if (samples) { - if (wait) - *samples = (c + *wait) << 3; - else - *samples = c << 3; - } + + c = 0; + for (;;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + if (++c >= len) break; + } + WDT_HIT(); + } + if (samples) { + if (wait) + *samples = (c + *wait) << 3; + else + *samples = c << 3; + } } //----------------------------------------------------------------------------- // DEMODULATE tag answer //----------------------------------------------------------------------------- static int DemodAnswer(uint8_t *received, uint8_t *dest, uint16_t samplecount) { - - int i, j; - int max = 0, maxPos = 0, skip = 4; - int k = 0; // this will be our return value - // First, correlate for SOF - for (i = 0; i < samplecount; 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 i, j; + int max = 0, maxPos = 0, skip = 4; + 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) - return k; - - i = maxPos + ARRAYLEN(FrameSOF) / skip; + // First, correlate for SOF + for (i = 0; i < samplecount; 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)); - uint8_t outBuf[ISO15_MAX_FRAME]; - 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 (MF_DBGLEVEL >= MF_DBG_EXTENDED) - // Dbprintf("Corr1 %d, Corr0 %d, CorrEOF %d", corr1, corr0, corrEOF); + // greg - If correlation is less than 1 then there's little point in continuing + if ((max / (ARRAYLEN(FrameSOF) / skip)) < 1) + return k; - if (corrEOF > corr1 && corrEOF > corr0) - break; - - 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)) >= samplecount-1) { - //Dbprintf("[!] ran off end! %d | %d",( i + (int)ARRAYLEN(FrameEOF)), samplecount-1); - break; - } - } - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("ice: demod bytes %u", k); - - if (mask != 0x01) { // this happens, when we miss the EOF - - // TODO: for some reason this happens quite often - if (MF_DBGLEVEL >= MF_DBG_ERROR && k != 0) 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 - } + i = maxPos + ARRAYLEN(FrameSOF) / skip; - for(i = 0; i < k; i++) - received[i] = outBuf[i]; + uint8_t outBuf[ISO15_MAX_FRAME]; + 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 (DBGLEVEL >= DBG_EXTENDED) + // Dbprintf("Corr1 %d, Corr0 %d, CorrEOF %d", corr1, corr0, corrEOF); - // return the number of bytes demodulated - return k; + if (corrEOF > corr1 && corrEOF > corr0) + break; + + 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)) >= samplecount - 1) { + //Dbprintf("[!] ran off end! %d | %d",( i + (int)ARRAYLEN(FrameEOF)), samplecount-1); + break; + } + } + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("ice: demod bytes %u", k); + + if (mask != 0x01) { // this happens, when we miss the EOF + + // TODO: for some reason this happens quite often + if (DBGLEVEL >= DBG_ERROR && k != 0) 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 + } + + for (i = 0; i < k; i++) + received[i] = outBuf[i]; + + // return the number of bytes demodulated + return k; } // Read from Tag // Parameters: -// received -// samples -// elapsed -// returns: -// number of decoded bytes +// received +// samples +// elapsed +// returns: +// number of decoded bytes // logging enabled static int GetIso15693AnswerFromTag(uint8_t *received, int *elapsed) { #define SIGNAL_BUFF_SIZE 15000 - // get current clock - uint32_t time_0 = GetCountSspClk(); - uint32_t time_stop = 0; - bool getNext = false; - int counter = 0, ci = 0, cq = 0; - uint8_t *buf = BigBuf_malloc(SIGNAL_BUFF_SIZE); + // get current clock + uint32_t time_0 = GetCountSspClk(); + uint32_t time_stop = 0; + bool getNext = false; + int counter = 0, ci, cq = 0; + uint8_t *buf = BigBuf_malloc(SIGNAL_BUFF_SIZE); - if (elapsed) *elapsed = 0; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + if (elapsed) *elapsed = 0; - for(;;) { - WDT_HIT(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; //0x43; - // To make use of exact timing of next command from reader!! - if (elapsed) (*elapsed)++; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + for (;;) { + WDT_HIT(); - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; //0x43; + // To make use of exact timing of next command from reader!! + if (elapsed)(*elapsed)++; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - // 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. - // iceman 2016, amplitude sqrt(abs(i) + abs(q)) - if (getNext) { - - buf[counter++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1)); - - if (counter >= SIGNAL_BUFF_SIZE) - break; - } else { - cq = ci; - } - getNext = !getNext; - } - } - time_stop = GetCountSspClk() - time_0 ; - int len = DemodAnswer(received, buf, counter); - LogTrace(received, len, time_0 << 4, time_stop << 4, NULL, false); - BigBuf_free(); - return len; + ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; + ci = ABS(ci); + + // 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. + // iceman 2016, amplitude sqrt(abs(i) + abs(q)) + if (getNext) { + + buf[counter++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + + if (counter >= SIGNAL_BUFF_SIZE) + break; + } else { + cq = ci; + } + getNext = !getNext; + } + } + time_stop = GetCountSspClk() - time_0 ; + int len = DemodAnswer(received, buf, counter); + LogTrace(received, len, time_0 << 4, time_stop << 4, NULL, false); + BigBuf_free(); + return len; } @@ -437,45 +437,45 @@ static int GetIso15693AnswerFromTag(uint8_t *received, int *elapsed) { // logging enable, static int GetIso15693AnswerFromSniff(uint8_t *received, int *samples, int *elapsed) { - bool getNext = false; - int counter = 0, ci = 0, cq = 0; - uint32_t time_0 = 0, time_stop = 0; - uint8_t *buf = BigBuf_get_addr(); + bool getNext = false; + int counter = 0, ci, cq = 0; + uint32_t time_0 = 0, time_stop = 0; + uint8_t *buf = BigBuf_get_addr(); - // get current clock - time_0 = GetCountSspClk(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - - for(;;) { - WDT_HIT(); + // get current clock + time_0 = GetCountSspClk(); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - - // 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) { + for (;;) { + WDT_HIT(); - buf[counter++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1)); + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if(counter >= 20000) - break; - } else { - cq = ci; - } - getNext = !getNext; - } - } - - time_stop = GetCountSspClk() - time_0; - int k = DemodAnswer(received, buf, counter); - LogTrace(received, k, time_0 << 4, time_stop << 4, NULL, false); - return k; + ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; + ci = ABS(ci); + + // 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) { + + buf[counter++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + + if (counter >= 20000) + break; + } else { + cq = ci; + } + getNext = !getNext; + } + } + + time_stop = GetCountSspClk() - time_0; + int k = DemodAnswer(received, buf, counter); + LogTrace(received, k, time_0 << 4, time_stop << 4, NULL, false); + return k; } //----------------------------------------------------------------------------- @@ -484,134 +484,134 @@ static int GetIso15693AnswerFromSniff(uint8_t *received, int *samples, int *elap // so that it can be downloaded to a PC and processed there. //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - int c = 0, getNext = false; - int ci = 0, cq = 0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Now send the command - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - SpinDelay(200); + int c = 0, getNext = false; + int ci, cq = 0; - uint8_t *buf = BigBuf_get_addr(); - - uint32_t time_start = GetCountSspClk(); - uint8_t cmd[CMD_ID_RESP] = {0}; - BuildIdentifyRequest(cmd); - - // sending command - c = 0; - for(;;) { - WDT_HIT(); - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ToSend[c]; - c++; - if(c == ToSendMax + 3) { - break; - } - } - } + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); - - LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + // Now send the command + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + SpinDelay(200); - c = 0; - for(;;) { - WDT_HIT(); - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t *buf = BigBuf_get_addr(); - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - - // 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. - // iceman 2016, amplitude sqrt(abs(i) + abs(q)) - if (getNext) { - - buf[c++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1)); - - if (c >= 7000) break; - - } else { - cq = ci; - } - getNext = !getNext; - } - } + uint32_t time_start = GetCountSspClk(); + uint8_t cmd[CMD_ID_RESP] = {0}; + BuildIdentifyRequest(cmd); + + // sending command + c = 0; + for (;;) { + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + c++; + if (c == ToSendMax + 3) { + break; + } + } + } + + + LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + + c = 0; + for (;;) { + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + + ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; + ci = ABS(ci); + + // 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. + // iceman 2016, amplitude sqrt(abs(i) + abs(q)) + if (getNext) { + + buf[c++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + + if (c >= 7000) break; + + } else { + cq = ci; + } + getNext = !getNext; + } + } } // switch_off, initreader, no logging void RecordRawAdcSamplesIso15693(void) { - int c = 0, getNext = false; - int ci = 0, cq = 0; - - Iso15693InitReader(); + int c = 0, getNext = false; + int ci, cq = 0; - uint8_t *buf = BigBuf_get_addr(); + Iso15693InitReader(); - for(;;) { - WDT_HIT(); + uint8_t *buf = BigBuf_get_addr(); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + for (;;) { + WDT_HIT(); - ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; - ci = ABS(ci); - // 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) { - - buf[c++] = (uint8_t)(MAX(ci,cq) + (MIN(ci, cq) >> 1)); + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if(c >= 7000) - break; - } else { - cq = ci; - } + ci = (int8_t)AT91C_BASE_SSC->SSC_RHR; + ci = ABS(ci); + // 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) { - getNext = !getNext; - } - } - - Dbprintf("done"); - switch_off(); + buf[c++] = (uint8_t)(MAX(ci, cq) + (MIN(ci, cq) >> 1)); + + if (c >= 7000) + break; + } else { + cq = ci; + } + + getNext = !getNext; + } + } + + Dbprintf("done"); + switch_off(); } -// Initialize the proxmark as iso15k reader +// Initialize the proxmark as iso15k reader // (this might produces glitches that confuse some tags void Iso15693InitReader(void) { - LEDsoff(); - clear_trace(); - set_tracing(true); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + LEDsoff(); + clear_trace(); + set_tracing(true); - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(10); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - FpgaSetupSsc(); + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(10); - // Give the tags time to energize - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - SpinDelay(200); - - // Start the timer - StartCountSspClk(); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - LED_A_ON(); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(200); + + // Start the timer + StartCountSspClk(); + + LED_A_ON(); } /////////////////////////////////////////////////////////////////////// @@ -621,171 +621,172 @@ void Iso15693InitReader(void) { // 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(uint8_t *out) { - - uint8_t cmd[CMD_ID_RESP] = {0, ISO15_CMD_INVENTORY, 0, 0, 0}; - // flags - cmd[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - // no mask - cmd[2] = 0x00; - // CRC - AddCrc(cmd, 3); - // coding as high speed (1 out of 4) - CodeIso15693AsReader(cmd, CMD_ID_RESP); - memcpy(out, cmd, CMD_ID_RESP); +// It expects "cmdout" to be at least CMD_ID_RESP large +static void BuildIdentifyRequest(uint8_t *cmdout) { + uint8_t cmd[CMD_ID_RESP] = {0, ISO15_CMD_INVENTORY, 0, 0, 0}; + // flags + cmd[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + // no mask + cmd[2] = 0x00; + // CRC + AddCrc15(cmd, 3); + // coding as high speed (1 out of 4) + CodeIso15693AsReader(cmd, CMD_ID_RESP); + memcpy(cmdout, cmd, CMD_ID_RESP); } // uid is in transmission order (which is reverse of display order) /* static void BuildReadBlockRequest(uint8_t **out, uint8_t *uid, uint8_t blockNumber ) { - uint8_t cmd[CMD_READ_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; - // 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] = 0x20; - // UID may be optionally specified here - // 64-bit UID - cmd[2] = uid[0]; - cmd[3] = uid[1]; - cmd[4] = uid[2]; - cmd[5] = uid[3]; - cmd[6] = uid[4]; - cmd[7] = uid[5]; - cmd[8] = uid[6]; - cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) - // Block number to read - cmd[10] = blockNumber;//0x00; - // CRC - AddCrc(cmd, 11); - CodeIso15693AsReader(cmd, CMD_READ_RESP); - memcpy(out, cmd, CMD_ID_RESP); + uint8_t cmd[CMD_READ_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0,0}; + // 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] = 0x20; + // UID may be optionally specified here + // 64-bit UID + cmd[2] = uid[0]; + cmd[3] = uid[1]; + cmd[4] = uid[2]; + cmd[5] = uid[3]; + cmd[6] = uid[4]; + cmd[7] = uid[5]; + cmd[8] = uid[6]; + cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) + // Block number to read + cmd[10] = blockNumber;//0x00; + // CRC + AddCrc15(cmd, 11); + CodeIso15693AsReader(cmd, CMD_READ_RESP); + memcpy(out, cmd, CMD_ID_RESP); } */ // Now the VICC>VCD responses when we are simulating a tag -static void BuildInventoryResponse(uint8_t *out, uint8_t *uid) { +// It expects "out" to be at least CMD_INV_RESP large +static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid) { - uint8_t cmd[CMD_INV_RESP] = {0,0,0,0,0,0,0,0,0,0,0,0}; + uint8_t cmd[CMD_INV_RESP] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY //(1 << 2) | (1 << 5) | (1 << 1); - cmd[0] = 0; // - cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported - // 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; - // CRC - AddCrc(cmd, 10); - CodeIso15693AsReader(cmd, CMD_INV_RESP); - memcpy(out, cmd, CMD_ID_RESP); + cmd[0] = 0; // + cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + // 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; + // CRC + AddCrc15(cmd, 10); + CodeIso15693AsReader(cmd, CMD_INV_RESP); + memcpy(cmdout, cmd, CMD_INV_RESP); } // 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 return you a pointer to the received data -// If you do not need the answer use NULL for *recv[] -// return: lenght of received data +// 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 // logging enabled int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *outdata) { - int t_samples = 0, wait = 0, elapsed = 0, answer_len = 0; - - LEDsoff(); - - if (init) Iso15693InitReader(); - - LED_A_ON(); + int t_samples = 0, wait = 0, elapsed = 0, answer_len = 0; - if (!speed) - CodeIso15693AsReader256(send, sendlen); // low speed (1 out of 256) - else - CodeIso15693AsReader(send, sendlen); // high speed (1 out of 4) + LEDsoff(); - LED_A_INV(); - - uint32_t time_start = GetCountSspClk(); + if (init) Iso15693InitReader(); - TransmitTo15693Tag(ToSend, ToSendMax, &t_samples, &wait); - LogTrace(send, sendlen, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); - - // Now wait for a response - if (outdata != NULL) { - LED_B_INV(); - answer_len = GetIso15693AnswerFromTag(outdata, &elapsed); - } + LED_A_ON(); - LEDsoff(); - return answer_len; + if (!speed) + CodeIso15693AsReader256(send, sendlen); // low speed (1 out of 256) + else + CodeIso15693AsReader(send, sendlen); // high speed (1 out of 4) + + LED_A_INV(); + + uint32_t time_start = GetCountSspClk(); + + TransmitTo15693Tag(ToSend, ToSendMax, &t_samples, &wait); + LogTrace(send, sendlen, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); + + // Now wait for a response + if (outdata != NULL) { + LED_B_INV(); + answer_len = GetIso15693AnswerFromTag(outdata, &elapsed); + } + + LEDsoff(); + return answer_len; } // -------------------------------------------------------------------- -// Debug Functions +// Debug Functions // -------------------------------------------------------------------- // Decodes a message from a tag and displays its metadata and content #define DBD15STATLEN 48 void DbdecodeIso15693Answer(int len, uint8_t *d) { - char status[DBD15STATLEN+1] = {0}; - if (len > 3) { - if (d[0] & ( 1 << 3 )) - strncat(status, "ProtExt ", DBD15STATLEN); - if (d[0] & 1) { - // error - strncat(status, "Error ", DBD15STATLEN); - switch (d[1]) { - case 0x01: - strncat(status, "01: not supported", DBD15STATLEN); - break; - case 0x02: - strncat(status, "02: not recognized", DBD15STATLEN); - break; - case 0x03: - strncat(status, "03: opt not supported", DBD15STATLEN); - break; - case 0x0f: - strncat(status, "0F: no info", DBD15STATLEN); - break; - case 0x10: - strncat(status, "10: dont exist", DBD15STATLEN); - break; - case 0x11: - strncat(status, "11: lock again", DBD15STATLEN); - break; - case 0x12: - strncat(status, "12: locked", DBD15STATLEN); - break; - case 0x13: - strncat(status, "13: program error", DBD15STATLEN); - break; - case 0x14: - strncat(status, "14: lock error", DBD15STATLEN); - break; - default: - strncat(status, "unknown error", DBD15STATLEN); - } - strncat(status ," " ,DBD15STATLEN); - } else { - strncat(status ,"No error ", DBD15STATLEN); - } - - if (CheckCrc(d, len)) - strncat(status, "[+] crc OK", DBD15STATLEN); - else - strncat(status, "[!] crc fail", DBD15STATLEN); + if (len > 3) { + char status[DBD15STATLEN + 1] = {0}; + if (d[0] & (1 << 3)) + strncat(status, "ProtExt ", DBD15STATLEN - strlen(status)); + if (d[0] & 1) { + // error + strncat(status, "Error ", DBD15STATLEN - strlen(status)); + switch (d[1]) { + case 0x01: + strncat(status, "01: not supported", DBD15STATLEN - strlen(status)); + break; + case 0x02: + strncat(status, "02: not recognized", DBD15STATLEN - strlen(status)); + break; + case 0x03: + strncat(status, "03: opt not supported", DBD15STATLEN - strlen(status)); + break; + case 0x0f: + strncat(status, "0F: no info", DBD15STATLEN - strlen(status)); + break; + case 0x10: + strncat(status, "10: dont exist", DBD15STATLEN - strlen(status)); + break; + case 0x11: + strncat(status, "11: lock again", DBD15STATLEN - strlen(status)); + break; + case 0x12: + strncat(status, "12: locked", DBD15STATLEN - strlen(status)); + break; + case 0x13: + strncat(status, "13: program error", DBD15STATLEN - strlen(status)); + break; + case 0x14: + strncat(status, "14: lock error", DBD15STATLEN - strlen(status)); + break; + default: + strncat(status, "unknown error", DBD15STATLEN - strlen(status)); + } + strncat(status, " ", DBD15STATLEN - strlen(status)); + } else { + strncat(status, "No error ", DBD15STATLEN - strlen(status)); + } - if ( MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("%s", status); - } + if (CheckCrc15(d, len)) + strncat(status, "[+] crc OK", DBD15STATLEN - strlen(status)); + else + strncat(status, "[!] crc fail", DBD15STATLEN - strlen(status)); + + if (DBGLEVEL >= DBG_ERROR) Dbprintf("%s", status); + } } /////////////////////////////////////////////////////////////////////// @@ -799,204 +800,202 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { // ok // parameter is unused !?! void ReaderIso15693(uint32_t parameter) { - int answerLen1 = 0; - int tsamples = 0, wait = 0, elapsed = 0; - - uint8_t uid[8] = {0,0,0,0,0,0,0,0}; + int answerLen1 = 0; + int tsamples = 0, wait = 0, elapsed = 0; + // set up device/fpga + Iso15693InitReader(); - // set up device/fpga - Iso15693InitReader(); - - uint8_t *answer1 = BigBuf_malloc(50); - uint8_t *answer2 = BigBuf_malloc(50); + uint8_t *answer1 = BigBuf_malloc(50); + uint8_t *answer2 = BigBuf_malloc(50); - // Blank arrays - memset(answer1, 0x00, 50); - memset(answer2, 0x00, 50); + // Blank arrays + memset(answer1, 0x00, 50); + memset(answer2, 0x00, 50); - // Now send the IDENTIFY command - // FIRST WE RUN AN INVENTORY TO GET THE TAG UID - // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME - uint32_t time_start = GetCountSspClk(); - uint8_t cmd[CMD_ID_RESP] = {0}; - BuildIdentifyRequest( cmd ); - TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait); - LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); - - // Now wait for a response - answerLen1 = GetIso15693AnswerFromTag(answer1, &elapsed) ; + // Now send the IDENTIFY command + // FIRST WE RUN AN INVENTORY TO GET THE TAG UID + // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME + uint32_t time_start = GetCountSspClk(); + uint8_t cmd[CMD_ID_RESP] = {0}; + BuildIdentifyRequest(cmd); + TransmitTo15693Tag(ToSend, ToSendMax, &tsamples, &wait); + LogTrace(cmd, CMD_ID_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); - // we should do a better check than this - if (answerLen1 >= 12) { - uid[0] = answer1[9]; // always E0 - uid[1] = answer1[8]; // IC Manufacturer code - uid[2] = answer1[7]; - uid[3] = answer1[6]; - uid[4] = answer1[5]; - uid[5] = answer1[4]; - uid[6] = answer1[3]; - uid[7] = answer1[2]; - - if ( MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", - uid[0], uid[1], uid[2], uid[3], - uid[4], uid[5], uid[5], uid[6] - ); - } - // send UID back to client. - // arg0 = 1 = OK - // arg1 = len of response (12 bytes) - // arg2 = rtf - // asbytes = uid. - cmd_send(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); - } + // Now wait for a response + answerLen1 = GetIso15693AnswerFromTag(answer1, &elapsed) ; - if ( MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen1); - DbdecodeIso15693Answer(answerLen1, answer1); - Dbhexdump(answerLen1, answer1, true); - } + // we should do a better check than this + if (answerLen1 >= 12) { + uint8_t uid[8]; + uid[0] = answer1[9]; // always E0 + uid[1] = answer1[8]; // IC Manufacturer code + uid[2] = answer1[7]; + uid[3] = answer1[6]; + uid[4] = answer1[5]; + uid[5] = answer1[4]; + uid[6] = answer1[3]; + uid[7] = answer1[2]; - switch_off(); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], uid[5], uid[6] + ); + } + // send UID back to client. + // arg0 = 1 = OK + // arg1 = len of response (12 bytes) + // arg2 = rtf + // asbytes = uid. + reply_old(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); + } + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen1); + DbdecodeIso15693Answer(answerLen1, answer1); + Dbhexdump(answerLen1, answer1, true); + } + + switch_off(); } // 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, uint8_t *uid) { - - LEDsoff(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - // Start from off (no field generated) + + LEDsoff(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - LED_A_ON(); + SpinDelay(200); - uint32_t time_start = 0; - int ans = 0, samples = 0, tsamples = 0; - int wait = 0, elapsed = 0; + LED_A_ON(); - Dbprintf("ISO-15963 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]); + uint32_t time_start; + int samples = 0, tsamples = 0; + int wait = 0, elapsed = 0; - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); + Dbprintf("ISO-15963 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]); - LED_C_ON(); + uint8_t buf[ISO15_MAX_FRAME]; + memset(buf, 0x00, sizeof(buf)); - // Build a suitable reponse to the reader INVENTORY cocmmand - // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. - uint8_t cmd[CMD_INV_RESP] = {0}; - BuildInventoryResponse(cmd, uid); - - while (!BUTTON_PRESS() && !usb_poll_validate_length() ) { - WDT_HIT(); - - // Listen to reader - ans = GetIso15693AnswerFromSniff(buf, &samples, &elapsed) ; + LED_C_ON(); - // we should do a better check than this - if (ans >= 1 ) { - - time_start = GetCountSspClk(); - TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); - LogTrace(cmd, CMD_INV_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("[+] %d octets read from reader command: %x %x %x %x %x %x %x %x", ans, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7] - ); - } - } - } - switch_off(); + // Build a suitable reponse to the reader INVENTORY cocmmand + // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. + uint8_t cmd[CMD_INV_RESP] = {0}; + BuildInventoryResponse(cmd, uid); + + while (!BUTTON_PRESS() && !data_available()) { + WDT_HIT(); + + // Listen to reader + int ans = GetIso15693AnswerFromSniff(buf, &samples, &elapsed) ; + + // we should do a better check than this + if (ans >= 1) { + + time_start = GetCountSspClk(); + TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait); + LogTrace(cmd, CMD_INV_RESP, time_start << 4, (GetCountSspClk() - time_start) << 4, NULL, true); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] %d octets read from reader command: %x %x %x %x %x %x %x %x", ans, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7] + ); + } + } + } + switch_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) { +void BruteforceIso15693Afi(uint32_t speed) { - uint8_t data[7] = {0,0,0,0,0,0,0}; - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); - int datalen = 0, recvlen = 0; - - Iso15693InitReader(); - - // first without AFI - // 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 - AddCrc(data, 3); - datalen += 2; - - recvlen = SendDataTag(data, datalen, false, speed, buf); - - WDT_HIT(); - - if (recvlen >= 12) { - Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2) ); - } - - // now with AFI - data[0] |= ISO15_REQINV_AFI; - //data[1] = ISO15_CMD_INVENTORY; - data[2] = 0; // AFI - data[3] = 0; // mask length - - for (uint16_t i = 0; i < 256; i++) { - data[2] = i & 0xFF; - AddCrc(data, 4); - datalen += 2; - recvlen = SendDataTag(data, datalen, false, speed, buf); - WDT_HIT(); - if (recvlen >= 12) { - Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2) ); - } - - if (BUTTON_PRESS()) { - DbpString("button pressed, aborting.."); - break; - } - } - - DbpString("AFI Bruteforcing done."); - switch_off(); + uint8_t data[7] = {0, 0, 0, 0, 0, 0, 0}; + uint8_t buf[ISO15_MAX_FRAME]; + memset(buf, 0x00, sizeof(buf)); + int datalen = 0, recvlen = 0; + + Iso15693InitReader(); + + // first without AFI + // 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 + AddCrc15(data, 3); + datalen += 2; + + recvlen = SendDataTag(data, datalen, false, speed, buf); + + WDT_HIT(); + + if (recvlen >= 12) { + Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2)); + } + + // now with AFI + data[0] |= ISO15_REQINV_AFI; + //data[1] = ISO15_CMD_INVENTORY; + data[2] = 0; // AFI + data[3] = 0; // mask length + + for (uint16_t i = 0; i < 256; i++) { + data[2] = i & 0xFF; + AddCrc15(data, 4); + datalen += 2; + recvlen = SendDataTag(data, datalen, false, speed, buf); + WDT_HIT(); + if (recvlen >= 12) { + Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); + } + + if (BUTTON_PRESS()) { + DbpString("button pressed, aborting.."); + break; + } + } + + DbpString("AFI Bruteforcing done."); + switch_off(); } // Allows to directly send commands to the tag via the client -// Has to increase dialog between device and client. +// Has to increase dialog between device and client. void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) { - bool init = true; - int buflen = 0; - uint8_t buf[ISO15_MAX_FRAME]; - memset(buf, 0x00, sizeof(buf)); + bool init = true; + int buflen = 0; + uint8_t buf[ISO15_MAX_FRAME]; + memset(buf, 0x00, sizeof(buf)); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - DbpString("[+] SEND"); - Dbhexdump(datalen, data, true); - } - - buflen = SendDataTag(data, datalen, init, speed, (recv ? buf : NULL)); - - if (recv) { - buflen = (buflen > ISO15_MAX_FRAME) ? ISO15_MAX_FRAME : buflen; - - LED_B_ON(); - cmd_send(CMD_ACK, buflen, 0, 0, buf, buflen); - LED_B_OFF(); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - DbpString("[+] RECV"); - DbdecodeIso15693Answer(buflen, buf); - Dbhexdump(buflen, buf, true); - } - } else { - cmd_send(CMD_ACK,1,0,0,0,0); - } -} \ No newline at end of file + if (DBGLEVEL >= DBG_EXTENDED) { + DbpString("[+] SEND"); + Dbhexdump(datalen, data, true); + } + + buflen = SendDataTag(data, datalen, init, speed, (recv ? buf : NULL)); + + if (recv) { + buflen = (buflen > ISO15_MAX_FRAME) ? ISO15_MAX_FRAME : buflen; + + LED_B_ON(); + reply_old(CMD_ACK, buflen, 0, 0, buf, buflen); + LED_B_OFF(); + + if (DBGLEVEL >= DBG_EXTENDED) { + DbpString("[+] RECV"); + DbdecodeIso15693Answer(buflen, buf); + Dbhexdump(buflen, buf, true); + } + } else { + reply_old(CMD_ACK, 1, 0, 0, 0, 0); + } +} diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 3a45c4c67..1b689550d 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz // 2016 Iceman -// 2018 AntiCat (rwd rewritten) +// 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 @@ -16,7 +16,7 @@ #include "legic_prng.h" /* legic PRNG impl */ #include "legic.h" /* legic_card_select_t struct */ -static uint8_t* legic_mem; /* card memory, used for read, write and sim */ +static uint8_t *legic_mem; /* card memory, used for read, write */ static legic_card_select_t card;/* metadata of currently selected card */ static crc_t legic_crc; @@ -50,21 +50,21 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ #define WRITE_LOWERLIMIT 4 /* UID and MCC are not writable */ #define INPUT_THRESHOLD 8 /* heuristically determined, lower values */ - /* lead to detecting false ack during write */ +/* lead to detecting false ack during write */ //----------------------------------------------------------------------------- // I/O interface abstraction (FPGA -> ARM) //----------------------------------------------------------------------------- static inline uint8_t rx_byte_from_fpga() { - for(;;) { - WDT_HIT(); + for (;;) { + WDT_HIT(); - // wait for byte be become available in rx holding register - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - return AT91C_BASE_SSC->SSC_RHR; + // wait for byte be become available in rx holding register + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + return AT91C_BASE_SSC->SSC_RHR; + } } - } } //----------------------------------------------------------------------------- @@ -81,13 +81,15 @@ static inline uint8_t rx_byte_from_fpga() { // To reduce CPU time the amplitude is approximated by using linear functions: // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // -// Note: The SSC receiver is never synchronized the calculation my be performed +// Note: The SSC receiver is never synchronized the calculation may be performed // on a i/q pair from two subsequent correlations, but does not matter. static inline int32_t sample_power() { - int32_t q = (int8_t)rx_byte_from_fpga(); q = ABS(q); - int32_t i = (int8_t)rx_byte_from_fpga(); i = ABS(i); + int32_t q = (int8_t)rx_byte_from_fpga(); + q = ABS(q); + int32_t i = (int8_t)rx_byte_from_fpga(); + i = ABS(i); - return MAX(i, q) + (MIN(i, q) >> 1); + return MAX(i, q) + (MIN(i, q) >> 1); } // Returns a demedulated bit @@ -98,13 +100,13 @@ static inline int32_t sample_power() { // Note: The demodulator would be drifting (18.9us * 5 != 100us), rx_frame // has a delay loop that aligns rx_bit calls to the TAG tx timeslots. static inline bool rx_bit() { - int32_t power; + int32_t power; - for(size_t i = 0; i<5; ++i) { - power = sample_power(); - } + for (size_t i = 0; i < 5; ++i) { + power = sample_power(); + } - return (power > INPUT_THRESHOLD); + return (power > INPUT_THRESHOLD); } //----------------------------------------------------------------------------- @@ -117,15 +119,15 @@ static inline bool rx_bit() { //----------------------------------------------------------------------------- static inline void tx_bit(bool bit) { - // insert pause - LOW(GPIO_SSC_DOUT); - last_frame_end += RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; - HIGH(GPIO_SSC_DOUT); + // insert pause + LOW(GPIO_SSC_DOUT); + last_frame_end += RWD_TIME_PAUSE; + while (GET_TICKS < last_frame_end) { }; + HIGH(GPIO_SSC_DOUT); - // return to high, wait for bit periode to end - last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; + // return to high, wait for bit periode to end + last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; + while (GET_TICKS < last_frame_end) { }; } //----------------------------------------------------------------------------- @@ -139,162 +141,162 @@ static inline void tx_bit(bool bit) { //----------------------------------------------------------------------------- static void tx_frame(uint32_t frame, uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - // wait for next tx timeslot - last_frame_end += RWD_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + // wait for next tx timeslot + last_frame_end += RWD_FRAME_WAIT; + while (GET_TICKS < last_frame_end) { }; - // backup ts for trace log - uint32_t last_frame_start = last_frame_end; + // backup ts for trace log + uint32_t last_frame_start = 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); - }; + // 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); + }; - // add pause to mark end of the frame - LOW(GPIO_SSC_DOUT); - last_frame_end += RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; - HIGH(GPIO_SSC_DOUT); + // add pause to mark end of the frame + LOW(GPIO_SSC_DOUT); + last_frame_end += RWD_TIME_PAUSE; + while (GET_TICKS < last_frame_end) { }; + HIGH(GPIO_SSC_DOUT); - // log - uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; - LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true); + // log + uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true); } static uint32_t rx_frame(uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR + | FPGA_HF_READER_RX_XCORR_848_KHZ + | FPGA_HF_READER_RX_XCORR_QUARTER); - // hold sampling until card is expected to respond - last_frame_end += TAG_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + // hold sampling until card is expected to respond + last_frame_end += TAG_FRAME_WAIT; + while (GET_TICKS < last_frame_end) { }; - // backup ts for trace log - uint32_t last_frame_start = last_frame_end; + // backup ts for trace log + uint32_t last_frame_start = last_frame_end; - uint32_t frame = 0; - for(uint8_t i = 0; i < len; i++) { - frame |= (rx_bit() ^ legic_prng_get_bit()) << i; - legic_prng_forward(1); + uint32_t frame = 0; + for (uint8_t i = 0; i < len; ++i) { + frame |= (rx_bit() ^ legic_prng_get_bit()) << i; + legic_prng_forward(1); - // rx_bit runs only 95us, resync to TAG_BIT_PERIOD - last_frame_end += TAG_BIT_PERIOD; - while(GET_TICKS < last_frame_end) { }; - } + // rx_bit runs only 95us, resync to TAG_BIT_PERIOD + last_frame_end += TAG_BIT_PERIOD; + while (GET_TICKS < last_frame_end) { }; + } - // log - uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)}; - LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); + // log + uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); - return frame; + return frame; } static bool rx_ack() { - // change fpga into rx mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); + // change fpga into rx mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR + | FPGA_HF_READER_RX_XCORR_848_KHZ + | FPGA_HF_READER_RX_XCORR_QUARTER); - // hold sampling until card is expected to respond - last_frame_end += TAG_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; + // hold sampling until card is expected to respond + last_frame_end += TAG_FRAME_WAIT; + while (GET_TICKS < last_frame_end) { }; - // backup ts for trace log - uint32_t last_frame_start = last_frame_end; + // backup ts for trace log + uint32_t last_frame_start = last_frame_end; - uint32_t ack = 0; - for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { - // sample bit - ack = rx_bit(); - legic_prng_forward(1); + uint32_t ack = 0; + for (uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { + // sample bit + ack = rx_bit(); + legic_prng_forward(1); - // rx_bit runs only 95us, resync to TAG_BIT_PERIOD - last_frame_end += TAG_BIT_PERIOD; - while(GET_TICKS < last_frame_end) { }; + // rx_bit runs only 95us, resync to TAG_BIT_PERIOD + last_frame_end += TAG_BIT_PERIOD; + while (GET_TICKS < last_frame_end) { }; - // check if it was an ACK - if(ack) { - break; + // check if it was an ACK + if (ack) { + break; + } } - } - // log - uint8_t cmdbytes[] = {1, BYTEx(ack, 0)}; - LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); + // log + uint8_t cmdbytes[] = {1, BYTEx(ack, 0)}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); - return ack; + return ack; } //----------------------------------------------------------------------------- // Legic Reader //----------------------------------------------------------------------------- -int init_card(uint8_t cardtype, legic_card_select_t *p_card) { - p_card->tagtype = cardtype; +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; + 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 init_reader(bool clear_mem) { - // configure FPGA - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - LED_A_ON(); + // configure FPGA + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR + | FPGA_HF_READER_RX_XCORR_848_KHZ + | FPGA_HF_READER_RX_XCORR_QUARTER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + LED_A_ON(); - // configure SSC with defaults - FpgaSetupSsc(); + // configure SSC with defaults + FpgaSetupSsc(); - // 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; - HIGH(GPIO_SSC_DOUT); + // 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; + HIGH(GPIO_SSC_DOUT); - // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. - legic_mem = BigBuf_get_EM_addr(); - if(legic_mem) { - memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE); - } + // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. + legic_mem = BigBuf_get_EM_addr(); + if (legic_mem) { + memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE); + } - // start trace - clear_trace(); - set_tracing(true); + // start trace + clear_trace(); + set_tracing(true); - // init crc calculator - crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); + // init crc calculator + crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); - // start us timer - StartTicks(); + // start us timer + StartTicks(); } // Setup reader to card connection @@ -302,90 +304,90 @@ static void init_reader(bool clear_mem) { // The setup consists of a three way handshake: // - Transmit initialisation vector 7 bits // - Receive card type 6 bits -// - Acknowledge frame 6 bits -static uint32_t setup_phase_reader(uint8_t iv) { - // init coordination timestamp - last_frame_end = GET_TICKS; +// - Transmit Acknowledge 6 bits +static uint32_t setup_phase(uint8_t iv) { + // init coordination timestamp + last_frame_end = GET_TICKS; - // 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 card charge for 5ms. + last_frame_end += 7500; + while (GET_TICKS < last_frame_end) { }; - legic_prng_init(0); - tx_frame(iv, 7); + legic_prng_init(0); + tx_frame(iv, 7); - // configure iv - legic_prng_init(iv); - legic_prng_forward(2); + // configure prng + legic_prng_init(iv); + legic_prng_forward(2); - // receive card type - int32_t card_type = rx_frame(6); - legic_prng_forward(3); + // 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; - } + // 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 card_type; } 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); + crc_clear(&legic_crc); + crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz); + return crc_finish(&legic_crc); } static int16_t read_byte(uint16_t index, uint8_t cmd_sz) { - uint16_t cmd = (index << 1) | LEGIC_READ; + uint16_t cmd = (index << 1) | LEGIC_READ; - // 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(); + // 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); + // 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; - } + // 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); + legic_prng_forward(1); - return byte; + return byte; } // 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 + 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 - // send write command - LED_C_ON(); - legic_prng_forward(2); - tx_frame(cmd, addr_sz + 1 + 8 + 4); // cmd_sz = addr_sz + cmd + data + crc - legic_prng_forward(3); - LED_C_OFF(); + // send write command + LED_C_ON(); + legic_prng_forward(2); + tx_frame(cmd, addr_sz + 1 + 8 + 4); // cmd_sz = addr_sz + cmd + data + crc + legic_prng_forward(3); + LED_C_OFF(); - // wait for ack - return rx_ack(); + // wait for ack + return rx_ack(); } //----------------------------------------------------------------------------- @@ -394,114 +396,110 @@ bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) { // Only this functions are public / called from appmain.c //----------------------------------------------------------------------------- void LegicRfInfo(void) { - // configure ARM and FPGA - init_reader(false); + // configure ARM and FPGA + init_reader(false); - // establish shared secret and detect card type - uint8_t card_type = setup_phase_reader(0x01); - if(init_card(card_type, &card) != 0) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; - } - - // read UID - for(uint8_t i = 0; i < sizeof(card.uid); ++i) { - int16_t byte = read_byte(i, card.cmdsize); - if(byte == -1) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; + // establish shared secret and detect card type + uint8_t card_type = setup_phase(0x01); + if (init_card(card_type, &card) != 0) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; } - card.uid[i] = byte & 0xFF; - } - // read MCC and check against UID - int16_t mcc = read_byte(4, card.cmdsize); - int16_t calc_mcc = CRC8Legic(card.uid, 4);; - if(mcc != calc_mcc) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; - } + // read UID + for (uint8_t i = 0; i < sizeof(card.uid); ++i) { + int16_t byte = read_byte(i, card.cmdsize); + if (byte == -1) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; + } + card.uid[i] = byte & 0xFF; + } - // OK - cmd_send(CMD_ACK, 1, 0, 0, (uint8_t*)&card, sizeof(legic_card_select_t)); + // read MCC and check against UID + int16_t mcc = read_byte(4, card.cmdsize); + int16_t calc_mcc = CRC8Legic(card.uid, 4);; + if (mcc != calc_mcc) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; + } + + // OK + reply_old(CMD_ACK, 1, 0, 0, (uint8_t *)&card, sizeof(legic_card_select_t)); OUT: - switch_off(); - StopTicks(); + switch_off(); + StopTicks(); } void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) { - // configure ARM and FPGA - init_reader(false); + // configure ARM and FPGA + init_reader(false); - // establish shared secret and detect card type - uint8_t card_type = setup_phase_reader(iv); - if(init_card(card_type, &card) != 0) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; - } - - // do not read beyond card memory - if(len + offset > card.cardsize) { - len = card.cardsize - offset; - } - - for(uint16_t i = 0; i < len; ++i) { - int16_t byte = read_byte(offset + i, card.cmdsize); - if(byte == -1) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; + // establish shared secret and detect card type + uint8_t card_type = setup_phase(iv); + if (init_card(card_type, &card) != 0) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; } - legic_mem[i] = byte; - } - // OK - cmd_send(CMD_ACK, 1, len, 0, legic_mem, len); + // do not read beyond card memory + if (len + offset > card.cardsize) { + len = card.cardsize - offset; + } + + for (uint16_t i = 0; i < len; ++i) { + int16_t byte = read_byte(offset + i, card.cmdsize); + if (byte == -1) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; + } + legic_mem[i] = byte; + } + + // OK + reply_old(CMD_ACK, 1, len, 0, legic_mem, len); OUT: - switch_off(); - StopTicks(); + switch_off(); + StopTicks(); } void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) { - // configure ARM and FPGA - init_reader(false); + // configure ARM and FPGA + init_reader(false); - // uid is not writeable - if(offset <= WRITE_LOWERLIMIT) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; - } - - // establish shared secret and detect card type - uint8_t card_type = setup_phase_reader(iv); - if(init_card(card_type, &card) != 0) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; - } - - // do not write beyond card memory - if(len + offset > card.cardsize) { - len = card.cardsize - offset; - } - - // write in reverse order, only then is DCF (decremental field) writable - while(len-- > 0 && !BUTTON_PRESS()) { - if(!write_byte(len + offset, data[len], card.addrsize)) { - Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]); - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); - goto OUT; + // uid is not writeable + if (offset <= WRITE_LOWERLIMIT) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; } - } - // OK - cmd_send(CMD_ACK, 1, len, 0, legic_mem, len); + // establish shared secret and detect card type + uint8_t card_type = setup_phase(iv); + if (init_card(card_type, &card) != 0) { + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; + } + + // do not write beyond card memory + if (len + offset > card.cardsize) { + len = card.cardsize - offset; + } + + // write in reverse order, only then is DCF (decremental field) writable + while (len-- > 0 && !BUTTON_PRESS()) { + if (!write_byte(len + offset, data[len], card.addrsize)) { + Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]); + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + goto OUT; + } + } + + // OK + reply_old(CMD_ACK, 1, len, 0, legic_mem, len); OUT: - switch_off(); - StopTicks(); -} - -void LegicRfSimulate(int phase, int frame, int reqresp) { - cmd_send(CMD_ACK, 0, 0, 0, 0, 0); //TODO Implement + switch_off(); + StopTicks(); } diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 4bcf04899..76c392257 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -1,5 +1,6 @@ -//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // (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 @@ -13,9 +14,8 @@ #include "proxmark3.h" -extern void LegicRfInfo(void); -extern void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv); -extern void LegicRfWriter(uint16_t offset, uint16_t byte, uint8_t iv, uint8_t *data); -extern void LegicRfSimulate(int phase, int frame, int reqresp); +void LegicRfInfo(void); +void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv); +void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data); #endif /* __LEGICRF_H */ diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c new file mode 100644 index 000000000..0500e3e32 --- /dev/null +++ b/armsrc/legicrfsim.c @@ -0,0 +1,485 @@ +//----------------------------------------------------------------------------- +// (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 "legicrf.h" + +#include "ticks.h" /* timers */ +#include "crc.h" /* legic crc-4 */ +#include "legic_prng.h" /* legic PRNG impl */ +#include "legic.h" /* legic_card_select_t struct */ + +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) { }; + + // backup ts for trace log + uint32_t last_frame_start = 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); + + // log + uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); +} + +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) { }; + + // backup ts for trace log + uint32_t last_frame_start = last_frame_end; + + // transmit ack (ack is not encrypted) + tx_bit(true); + legic_prng_forward(1); + + // disable subcarrier + LOW(GPIO_SSC_DOUT); + + // log + uint8_t cmdbytes[] = {1, 1}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false); +} + +// 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; + } + } + + // backup ts for trace log + uint32_t last_frame_start = last_frame_end; + + // receive frame + for (*len = 0; true; ++(*len)) { + // receive next bit + LED_B_ON(); + int8_t bit = rx_bit(); + LED_B_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; + + // log + uint8_t cmdbytes[] = {*len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; + LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true); + 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(); + + // 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_EM_addr(); + + // start trace + clear_trace(); + set_tracing(true); + + // 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() && !data_available()) { + 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"); + switch_off(); + StopTicks(); +} diff --git a/armsrc/legicrfsim.h b/armsrc/legicrfsim.h new file mode 100644 index 000000000..27fce129b --- /dev/null +++ b/armsrc/legicrfsim.h @@ -0,0 +1,19 @@ +//----------------------------------------------------------------------------- +// (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" + +void LegicRfSimulate(uint8_t tagtype); + +#endif /* __LEGICRFSIM_H */ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 5afce8549..09a1632cb 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -18,28 +18,22 @@ #include "lfsampling.h" #include "protocols.h" #include "usb_cdc.h" // for usb_poll_validate_length +#include "common.h" +#include "flashmem.h" // persistence on mem -#ifndef SHORT_COIL -# define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#endif -#ifndef OPEN_COIL -# define OPEN_COIL() HIGH(GPIO_SSC_DOUT) -#endif - - -#define START_GAP 48*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (15fc) -#define WRITE_GAP 18*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (10fc) -#define WRITE_0 24*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (24fc) -#define WRITE_1 54*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (56fc) 432 for T55x7; 448 for E5550 -#define READ_GAP 15*8 +//#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (15fc) +//#define WRITE_GAP 8*8 // 17*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (10fc) +//#define WRITE_0 15*8 // 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (24fc) +//#define WRITE_1 47*8 // 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (56fc) 432 for T55x7; 448 for E5550 +//#define READ_GAP 15*8 // 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) +// 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 +// WRITE_0 = 23*8 , 9*8 // 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 @@ -50,7 +44,103 @@ // new timer: // = 1us = 1.5ticks // 1fc = 8us = 12ticks +/* +Default LF T55xx config is set to: + startgap = 31*8 + writegap = 17*8 + write_0 = 15*8 + write_1 = 47*8 + read_gap = 15*8 +*/ +t55xx_config t_config = { 29 * 8, 17 * 8, 15 * 8, 47 * 8, 15 * 8 } ; +void printT55xxConfig(void) { + DbpString(_BLUE_("LF T55XX config")); + Dbprintf(" [a] startgap............%d*8 (%d)", t_config.start_gap / 8, t_config.start_gap); + Dbprintf(" [b] writegap............%d*8 (%d)", t_config.write_gap / 8, t_config.write_gap); + Dbprintf(" [c] write_0.............%d*8 (%d)", t_config.write_0 / 8, t_config.write_0); + Dbprintf(" [d] write_1.............%d*8 (%d)", t_config.write_1 / 8, t_config.write_1); + Dbprintf(" [e] readgap.............%d*8 (%d)", t_config.read_gap / 8, t_config.read_gap); +} + +void setT55xxConfig(uint8_t arg0, t55xx_config *c) { + + if (c->start_gap != 0) t_config.start_gap = c->start_gap; + if (c->write_gap != 0) t_config.write_gap = c->write_gap; + if (c->write_0 != 0) t_config.write_0 = c->write_0; + if (c->write_1 != 0) t_config.write_1 = c->write_1; + if (c->read_gap != 0) t_config.read_gap = c->read_gap; + + printT55xxConfig(); + +#ifdef WITH_FLASH + // shall persist to flashmem + if (arg0 == 0) { + return; + } + + if (!FlashInit()) { + return; + } + + uint8_t *buf = BigBuf_malloc(T55XX_CONFIG_LEN); + Flash_CheckBusy(BUSY_TIMEOUT); + uint16_t res = Flash_ReadDataCont(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); + if (res == 0) { + FlashStop(); + BigBuf_free(); + return; + } + + memcpy(buf, &t_config, T55XX_CONFIG_LEN); + + Flash_CheckBusy(BUSY_TIMEOUT); + Flash_WriteEnable(); + Flash_Erase4k(3, 0xD); + res = Flash_Write(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); + + if (res == T55XX_CONFIG_LEN && DBGLEVEL > 1) { + DbpString("T55XX Config save success"); + } + + BigBuf_free(); +#endif +} + +t55xx_config *getT55xxConfig(void) { + return &t_config; +} + +void loadT55xxConfig(void) { +#ifdef WITH_FLASH + if (!FlashInit()) { + return; + } + + uint8_t *buf = BigBuf_malloc(T55XX_CONFIG_LEN); + + Flash_CheckBusy(BUSY_TIMEOUT); + uint16_t isok = Flash_ReadDataCont(T55XX_CONFIG_OFFSET, buf, T55XX_CONFIG_LEN); + FlashStop(); + + // verify read mem is actual data. + uint8_t cntA = T55XX_CONFIG_LEN, cntB = T55XX_CONFIG_LEN; + for (int i = 0; i < T55XX_CONFIG_LEN; i++) { + if (buf[i] == 0xFF) cntA--; + if (buf[i] == 0x00) cntB--; + } + if (!cntA || !cntB) { + BigBuf_free(); + return; + } + + memcpy((uint8_t *)&t_config, buf, T55XX_CONFIG_LEN); + + if (isok == T55XX_CONFIG_LEN) { + if (DBGLEVEL > 1) DbpString("T55XX Config load success"); + } +#endif +} /** * Function to do a modulation and then get samples. @@ -61,98 +151,98 @@ */ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) { - // start timer - StartTicks(); + // start timer + StartTicks(); - // use lf config settings - sample_config *sc = getSamplingConfig(); + // use lf config settings + sample_config *sc = getSamplingConfig(); - // Make sure the tag is reset - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitMS(500); + // Make sure the tag is reset + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(500); - // clear read buffer - BigBuf_Clear_keep_EM(); + // clear read buffer + BigBuf_Clear_keep_EM(); - LFSetupFPGAForADC(sc->divisor, 1); - - // little more time for the tag to fully power up - WaitMS(200); - - // 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 - 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; - } + LFSetupFPGAForADC(sc->divisor, true); - // 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 + // little more time for the tag to fully power up + WaitMS(200); - // prime cmd_len to save time comparing strings while modulating - int cmd_len = 0; - while(command[cmd_len] != '\0' && command[cmd_len] != ' ') - cmd_len++; + // 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 + 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; + } - 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 != ' ') { - LED_D_ON(); - if (*(command++) == '0') - TurnReadLFOn(period_0); - else - TurnReadLFOn(period_1); + // 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 - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(delay_off); - } + // prime cmd_len to save time comparing strings while modulating + int cmd_len = 0; + while (command[cmd_len] != '\0' && command[cmd_len] != ' ') + cmd_len++; - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); - } + 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 != ' ') { + LED_D_ON(); + if (*(command++) == '0') + TurnReadLFOn(period_0); + else + TurnReadLFOn(period_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(delay_off); + } - // now do the read - DoAcquisition_config(false, 0); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); + } - // Turn off antenna - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // tell client we are done - cmd_send(CMD_ACK,0,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + + // now do the read + DoAcquisition_config(false, 0); + + // Turn off antenna + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // tell client we are done + reply_ng(CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K, PM3_SUCCESS, NULL, 0); } /* blank r/w tag data stream @@ -164,1508 +254,1621 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint [5555fe852c5555555555555555fe0000] */ -void ReadTItag(void) -{ - StartTicks(); - // some hardcoded initial params - // 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 +void ReadTItag(void) { + StartTicks(); + // some hardcoded initial params + // 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 - 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; + 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; - int i, cycles=0, samples=0; - // how many sample points fit in 16 cycles of each frequency - uint32_t sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI; - // when to tell if we're close enough to one freq or another - uint32_t threshold = (sampleslo - sampleshi + 1)>>1; + int i, cycles = 0, samples = 0; + // how many sample points fit in 16 cycles of each frequency + uint32_t sampleslo = (FSAMPLE << 4) / FREQLO, sampleshi = (FSAMPLE << 4) / FREQHI; + // when to tell if we're close enough to one freq or another + 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 + // 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 - // connects to SSP_DIN and the SSP_DOUT logic level controls - // whether we're modulating the antenna (high) - // or listening to the antenna (low) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + // Place FPGA in passthrough mode, in this mode the CROSS_LO line + // connects to SSP_DIN and the SSP_DOUT logic level controls + // whether we're modulating the antenna (high) + // or listening to the antenna (low) + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - // get TI tag data into the buffer - AcquireTiType(); + // get TI tag data into the buffer + AcquireTiType(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - for (i=0; i0) ) { - cycles++; - // after 16 cycles, measure the frequency - if (cycles>15) { - cycles=0; - samples=i-samples; // number of samples in these 16 cycles + for (i = 0; i < n - 1; i++) { + // count cycles by looking for lo to hi zero crossings + if ((dest[i] < 0) && (dest[i + 1] > 0)) { + cycles++; + // after 16 cycles, measure the frequency + if (cycles > 15) { + cycles = 0; + samples = i - samples; // number of samples in these 16 cycles - // 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; + // 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; - // check if the cycles fall close to the number - // expected for either the low or high frequency - if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) { - // low frequency represents a 1 - shift3 |= (1<<31); - } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) { - // high frequency represents a 0 - } else { - // probably detected a gay waveform or noise - // use this as gaydar or discard shift register and start again - shift3 = shift2 = shift1 = shift0 = 0; - } - samples = i; + // check if the cycles fall close to the number + // expected for either the low or high frequency + if ((samples > (sampleslo - threshold)) && (samples < (sampleslo + threshold))) { + // low frequency represents a 1 + shift3 |= (1u << 31); + } else if ((samples > (sampleshi - threshold)) && (samples < (sampleshi + threshold))) { + // high frequency represents a 0 + } else { + // probably detected a gay waveform or noise + // use this as gaydar or discard shift register and start again + shift3 = shift2 = shift1 = shift0 = 0; + } + samples = i; - // for each bit we receive, test if we've detected a valid tag + // for each bit we receive, test if we've detected a valid tag - // if we see 17 zeroes followed by 6 ones, we might have a tag - // remember the bits are backwards - if ( ((shift0 & 0x7fffff) == 0x7e0000) ) { - // if start and end bytes match, we have a tag so break out of the loop - if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) { - cycles = 0xF0B; //use this as a flag (ugly but whatever) - break; - } - } - } - } - } + // if we see 17 zeroes followed by 6 ones, we might have a tag + // remember the bits are backwards + if (((shift0 & 0x7fffff) == 0x7e0000)) { + // if start and end bytes match, we have a tag so break out of the loop + if (((shift0 >> 16) & 0xff) == ((shift3 >> 8) & 0xff)) { + cycles = 0xF0B; //use this as a flag (ugly but whatever) + break; + } + } + } + } + } - // if flag is set we have a tag - 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); + // if flag is set we have a tag + 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); - // align 16 bit crc into lower half of shift2 - shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; + // align 16 bit crc into lower half of shift2 + shift2 = ((shift2 >> 24) | (shift3 << 8)) & 0x0ffff; - // if r/w tag, check ident match - 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 ) { - DbpString("Error: Ident mismatch!"); - } else { - DbpString("Info: TI tag ident is valid"); - } - } else { - DbpString("Info: TI tag is readonly"); - } + // if r/w tag, check ident match + 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) { + DbpString("Error: Ident mismatch!"); + } else { + DbpString("Info: TI tag ident is valid"); + } + } else { + DbpString("Info: TI tag is readonly"); + } - // WARNING the order of the bytes in which we calc crc below needs checking - // i'm 99% sure the crc algorithm is correct, but it may need to eat the - // bytes in reverse or something - // calculate CRC - uint32_t crc=0; + // WARNING the order of the bytes in which we calc crc below needs checking + // i'm 99% sure the crc algorithm is correct, but it may need to eat the + // bytes in reverse or something + // calculate CRC + uint32_t crc = 0; - 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); - crc = update_crc16(crc, (shift1)&0xff); - crc = update_crc16(crc, (shift1>>8)&0xff); - crc = update_crc16(crc, (shift1>>16)&0xff); - crc = update_crc16(crc, (shift1>>24)&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); + crc = update_crc16(crc, (shift1) & 0xff); + crc = update_crc16(crc, (shift1 >> 8) & 0xff); + crc = update_crc16(crc, (shift1 >> 16) & 0xff); + 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); - if (crc != (shift2&0xffff)) { - Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); - } else { - DbpString("Info: CRC is good"); - } - } - StopTicks(); + Dbprintf("Info: Tag data: %x%08x, crc=%x", (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); + if (crc != (shift2 & 0xffff)) { + Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); + } else { + DbpString("Info: CRC is good"); + } + } + StopTicks(); } -void WriteTIbyte(uint8_t b) -{ - int i = 0; +void WriteTIbyte(uint8_t b) { + int i = 0; - // modulate 8 bits out to the antenna - for (i=0; i<8; i++) - { - if ( b & ( 1 << i ) ) { - // stop modulating antenna 1ms - LOW(GPIO_SSC_DOUT); - WaitUS(1000); - // modulate antenna 1ms - HIGH(GPIO_SSC_DOUT); - WaitUS(1000); - } else { - // stop modulating antenna 0.3ms - LOW(GPIO_SSC_DOUT); - WaitUS(300); - // modulate antenna 1.7ms - HIGH(GPIO_SSC_DOUT); - WaitUS(1700); - } - } + // modulate 8 bits out to the antenna + for (i = 0; i < 8; i++) { + if (b & (1 << i)) { + // stop modulating antenna 1ms + LOW(GPIO_SSC_DOUT); + WaitUS(1000); + // modulate antenna 1ms + HIGH(GPIO_SSC_DOUT); + WaitUS(1000); + } else { + // stop modulating antenna 0.3ms + LOW(GPIO_SSC_DOUT); + WaitUS(300); + // modulate antenna 1.7ms + HIGH(GPIO_SSC_DOUT); + WaitUS(1700); + } + } } -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 +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 - // clear buffer - uint32_t *buf = (uint32_t *)BigBuf_get_addr(); + // clear buffer + uint32_t *buf = (uint32_t *)BigBuf_get_addr(); - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); - // Set up the synchronous serial port - AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; - AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; + // Set up the synchronous serial port + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; - // 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; + // 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; - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; + AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; - // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long - // 48/2 = 24 MHz clock must be divided by 12 - AT91C_BASE_SSC->SSC_CMR = 12; + // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long + // 48/2 = 24 MHz clock must be divided by 12 + AT91C_BASE_SSC->SSC_CMR = 12; - AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; - // Transmit Clock Mode Register - AT91C_BASE_SSC->SSC_TCMR = 0; - // Transmit Frame Mode Register - AT91C_BASE_SSC->SSC_TFMR = 0; - // iceman, FpgaSetupSsc() ?? the code above? can it be replaced? - LED_D_ON(); + AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; + // Transmit Clock Mode Register + AT91C_BASE_SSC->SSC_TCMR = 0; + // Transmit Frame Mode Register + AT91C_BASE_SSC->SSC_TFMR = 0; + // iceman, FpgaSetupSsc() ?? the code above? can it be replaced? + LED_D_ON(); - // modulate antenna - HIGH(GPIO_SSC_DOUT); + // modulate antenna + HIGH(GPIO_SSC_DOUT); - // Charge TI tag for 50ms. - WaitMS(50); + // Charge TI tag for 50ms. + WaitMS(50); - // stop modulating antenna and listen - LOW(GPIO_SSC_DOUT); + // stop modulating antenna and listen + LOW(GPIO_SSC_DOUT); - LED_D_OFF(); + LED_D_OFF(); - i = 0; - for (;;) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - buf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer - i++; - if (i >= TIBUFLEN) break; - } - WDT_HIT(); - } + i = 0; + for (;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + buf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer + i++; + if (i >= TIBUFLEN) break; + } + WDT_HIT(); + } - // return stolen pin to SSP - AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; + // return stolen pin to SSP + 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(); - n = TIBUFLEN * 32; - - // unpack buffer - for (i = TIBUFLEN-1; i >= 0; i--) { - for (j = 0; j < 32; j++) { - if(buf[i] & (1 << j)) { - dest[--n] = 1; - } else { - dest[--n] = -1; - } - } - } - - // reset SSC - FpgaSetupSsc(); + char *dest = (char *)BigBuf_get_addr(); + n = TIBUFLEN * 32; + + // unpack buffer + for (i = TIBUFLEN - 1; i >= 0; i--) { + for (j = 0; j < 32; j++) { + if (buf[i] & (1u << j)) { + dest[--n] = 1; + } else { + dest[--n] = -1; + } + } + } + + // reset SSC + FpgaSetupSsc(); } // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc // if crc provided, it will be written with the data verbatim (even if bogus) // 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>>8)&0xff); - crc = update_crc16(crc, (idlo>>16)&0xff); - crc = update_crc16(crc, (idlo>>24)&0xff); - crc = update_crc16(crc, (idhi)&0xff); - crc = update_crc16(crc, (idhi>>8)&0xff); - crc = update_crc16(crc, (idhi>>16)&0xff); - crc = update_crc16(crc, (idhi>>24)&0xff); - } - Dbprintf("Writing to tag: %x%08x, crc=%x", idhi, idlo, crc); +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 >> 8) & 0xff); + crc = update_crc16(crc, (idlo >> 16) & 0xff); + crc = update_crc16(crc, (idlo >> 24) & 0xff); + crc = update_crc16(crc, (idhi) & 0xff); + crc = update_crc16(crc, (idhi >> 8) & 0xff); + crc = update_crc16(crc, (idhi >> 16) & 0xff); + crc = update_crc16(crc, (idhi >> 24) & 0xff); + } + Dbprintf("Writing to tag: %x%08x, crc=%x", idhi, idlo, crc); - // TI tags charge at 134.2Khz - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - // Place FPGA in passthrough mode, in this mode the CROSS_LO line - // connects to SSP_DIN and the SSP_DOUT logic level controls - // whether we're modulating the antenna (high) - // or listening to the antenna (low) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - StartTicks(); - - 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; + // TI tags charge at 134.2Khz + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + // Place FPGA in passthrough mode, in this mode the CROSS_LO line + // connects to SSP_DIN and the SSP_DOUT logic level controls + // whether we're modulating the antenna (high) + // or listening to the antenna (low) + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); + StartTicks(); - // writing algorithm: - // a high bit consists of a field off for 1ms and field on for 1ms - // a low bit consists of a field off for 0.3ms and field on for 1.7ms - // initiate a charge time of 50ms (field on) then immediately start writing bits - // start by writing 0xBB (keyword) and 0xEB (password) - // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) - // finally end with 0x0300 (write frame) - // all data is sent lsb first - // finish with 50ms programming time + LED_A_ON(); - // modulate antenna - HIGH(GPIO_SSC_DOUT); - WaitMS(50); // charge time + // 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; - WriteTIbyte(0xbb); // keyword - WriteTIbyte(0xeb); // password - WriteTIbyte( (idlo )&0xff ); - WriteTIbyte( (idlo>>8 )&0xff ); - WriteTIbyte( (idlo>>16)&0xff ); - WriteTIbyte( (idlo>>24)&0xff ); - WriteTIbyte( (idhi )&0xff ); - WriteTIbyte( (idhi>>8 )&0xff ); - WriteTIbyte( (idhi>>16)&0xff ); - WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo - WriteTIbyte( (crc )&0xff ); // crc lo - WriteTIbyte( (crc>>8 )&0xff ); // crc hi - WriteTIbyte(0x00); // write frame lo - WriteTIbyte(0x03); // write frame hi - HIGH(GPIO_SSC_DOUT); - WaitMS(50); // programming time + // writing algorithm: + // a high bit consists of a field off for 1ms and field on for 1ms + // a low bit consists of a field off for 0.3ms and field on for 1.7ms + // initiate a charge time of 50ms (field on) then immediately start writing bits + // start by writing 0xBB (keyword) and 0xEB (password) + // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) + // finally end with 0x0300 (write frame) + // all data is sent lsb first + // finish with 50ms programming time - LED_A_OFF(); + // modulate antenna + HIGH(GPIO_SSC_DOUT); + WaitMS(50); // charge time - // get TI tag data into the buffer - AcquireTiType(); + WriteTIbyte(0xbb); // keyword + WriteTIbyte(0xeb); // password + WriteTIbyte((idlo) & 0xff); + WriteTIbyte((idlo >> 8) & 0xff); + WriteTIbyte((idlo >> 16) & 0xff); + WriteTIbyte((idlo >> 24) & 0xff); + WriteTIbyte((idhi) & 0xff); + WriteTIbyte((idhi >> 8) & 0xff); + WriteTIbyte((idhi >> 16) & 0xff); + WriteTIbyte((idhi >> 24) & 0xff); // data hi to lo + WriteTIbyte((crc) & 0xff); // crc lo + WriteTIbyte((crc >> 8) & 0xff); // crc hi + WriteTIbyte(0x00); // write frame lo + WriteTIbyte(0x03); // write frame hi + HIGH(GPIO_SSC_DOUT); + WaitMS(50); // programming time - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use `lf ti read` to check"); - StopTicks(); + LED_A_OFF(); + + // get TI tag data into the buffer + AcquireTiType(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Now use `lf ti read` to check"); + StopTicks(); } // note: a call to FpgaDownloadAndGo(FPGA_BITSTREAM_LF) must be done before, but // this may destroy the bigbuf so be sure this is called before calling SimulateTagLowFrequencyEx -void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycles) { +void SimulateTagLowFrequencyEx(int period, int gap, bool ledcontrol, int numcycles) { - //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - SpinDelay(20); + // start us timer + StartTicks(); - int i = 0, x = 0; - uint8_t *buf = BigBuf_get_addr(); - - // set frequency, get values from 'lf config' command - sample_config *sc = getSamplingConfig(); + //FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + WaitMS(20); - if ( (sc->divisor == 1) || (sc->divisor < 0) || (sc->divisor > 255) ) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else if (sc->divisor == 0) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); - - 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; + int i = 0, x = 0; + uint8_t *buf = BigBuf_get_addr(); - for(;;) { + // set frequency, get values from 'lf config' command + sample_config *sc = getSamplingConfig(); - if ( numcycles > -1 ) { - if ( x != numcycles ) { - ++x; - } else { - // exit without turning of field - return; - } - } - - if (ledcontrol) LED_D_ON(); - - // wait until SSC_CLK goes HIGH - // used as a simple detection of a reader field? - while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - WDT_HIT(); - if ( usb_poll_validate_length() || BUTTON_PRESS() ) - goto OUT; - } - - if(buf[i]) - OPEN_COIL(); - else - SHORT_COIL(); - - //wait until SSC_CLK goes LOW - while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - WDT_HIT(); - //if ( usb_poll_validate_length() || BUTTON_PRESS() ) - if ( BUTTON_PRESS() ) - goto OUT; - } - - i++; - if(i == period) { - i = 0; - if (gap) { - SHORT_COIL(); - SpinDelayUs(gap); - } - } - - if (ledcontrol) LED_D_OFF(); - } -OUT: - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + if ((sc->divisor == 1) || (sc->divisor < 0) || (sc->divisor > 255)) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else if (sc->divisor == 0) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); + + 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; + + uint16_t check = 0; + + for (;;) { + + if (numcycles > -1) { + if (x != numcycles) { + ++x; + } else { + // exit without turning off field + return; + } + } + + if (ledcontrol) LED_D_ON(); + + // wait until SSC_CLK goes HIGH + // used as a simple detection of a reader field? + while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { + WDT_HIT(); + if (check == 1000) { + if (data_available() || BUTTON_PRESS()) + goto OUT; + check = 0; + } + ++check; + } + + if (ledcontrol) LED_D_OFF(); + + if (buf[i]) + OPEN_COIL(); + else + SHORT_COIL(); + + check = 0; + + //wait until SSC_CLK goes LOW + while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { + WDT_HIT(); + if (check == 1000) { + if (data_available() || BUTTON_PRESS()) + goto OUT; + check = 0; + } + ++check; + } + + i++; + if (i == period) { + i = 0; + if (gap) { + SHORT_COIL(); + WaitUS(gap); + } + } + } +OUT: + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); } -void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { - SimulateTagLowFrequencyEx(period, gap, ledcontrol, -1); +void SimulateTagLowFrequency(int period, int gap, bool ledcontrol) { + SimulateTagLowFrequencyEx(period, gap, ledcontrol, -1); } #define DEBUG_FRAME_CONTENTS 1 -void SimulateTagLowFrequencyBidir(int divisor, int t0) -{ +void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen) { } // compose fc/5 fc/8 waveform (FSK1) // compose fc/8 fc/10 waveform (FSK2) -// also manchester, -static void fc(int c, int *n) -{ - uint8_t *dest = BigBuf_get_addr(); - int idx; +// also manchester, +static void fc(int c, int *n) { + uint8_t *dest = BigBuf_get_addr(); + 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; - } + // 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; + } - // an fc/8 encoded bit is a bit pattern of 11110000 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; - } - } + // an fc/8 encoded bit is a bit pattern of 11110000 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; + } + } - // an fc/10 encoded bit is a bit pattern of 1111100000 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; - } - } + // an fc/10 encoded bit is a bit pattern of 1111100000 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; + } + } } // special start of frame marker containing invalid bit sequences // this one is focused on HID, with manchester encoding. -static void fcSTT(int *n) { - 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 +static void fcSTT(int *n) { + 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 } // 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; +static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) { + uint8_t *dest = BigBuf_get_addr(); + uint8_t halfFC = fc >> 1; + uint8_t wavesPerClock = clock / fc; + uint8_t mod = clock % fc; //modifier - // 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; - } + // 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) { + uint8_t modAdj = fc / mod; //how often to apply modifier + bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk = true; + (*modCnt)++; + + if (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 (!modAdjOk) { //fsk1 + memset(dest + (*n), 0, mod - (mod >> 1)); + memset(dest + (*n) + (mod - (mod >> 1)), 1, mod >> 1); + *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 CmdHIDsimTAGEx( uint32_t hi, uint32_t lo, int ledcontrol, int numcycles) { +void CmdHIDsimTAGEx(uint32_t hi, uint32_t lo, bool ledcontrol, int numcycles) { - if (hi > 0xFFF) { - DbpString("[!] tags can only have 44 bits. - USE lf simfsk for larger tags"); - return; - } - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - set_tracing(false); - - int n = 0, i = 0; - /* - HID tag bitstream format - The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits - A 1 bit is represented as 6 fc8 and 5 fc10 patterns (manchester 10) during 2 clock periods. (1bit = 1clock period) - A 0 bit is represented as 5 fc10 and 6 fc8 patterns (manchester 01) - A fc8 is inserted before every 4 bits - A special start of frame pattern is used consisting a0b0 where a and b are neither 0 - nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) + if (hi > 0xFFF) { + DbpString("[!] tags can only have 44 bits. - USE lf simfsk for larger tags"); + return; + } - FSK2a - bit 1 = fc10 - bit 0 = fc8 - */ + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + set_tracing(false); - fc(0, &n); + int n = 0, i = 0; + /* + HID tag bitstream format + The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits + A 1 bit is represented as 6 fc8 and 5 fc10 patterns (manchester 10) during 2 clock periods. (1bit = 1clock period) + A 0 bit is represented as 5 fc10 and 6 fc8 patterns (manchester 01) + A fc8 is inserted before every 4 bits + A special start of frame pattern is used consisting a0b0 where a and b are neither 0 + nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) - // special start of frame marker containing invalid bit sequences - fcSTT(&n); - - // 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 - } - } + FSK2a + bit 1 = fc10 + bit 0 = fc8 + */ - // manchester encode bits 31 to 0 - 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 - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } + fc(0, &n); - if (ledcontrol) LED_A_ON(); - SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles); - if (ledcontrol) LED_A_OFF(); + // special start of frame marker containing invalid bit sequences + fcSTT(&n); + + // 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 31 to 0 + 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 + } else { + fc(8, &n); + fc(10, &n); // high-low transition + } + } + + if (ledcontrol) LED_A_ON(); + SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles); + if (ledcontrol) LED_A_OFF(); } -void CmdHIDsimTAG( uint32_t hi, uint32_t lo, int ledcontrol) { - CmdHIDsimTAGEx( hi, lo, ledcontrol, -1); - DbpString("[!] simulation finished"); +void CmdHIDsimTAG(uint32_t hi, uint32_t lo, bool ledcontrol) { + CmdHIDsimTAGEx(hi, lo, ledcontrol, -1); + reply_ng(CMD_HID_SIM_TAG, PM3_EOPABORTED, NULL, 0); } // 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 STT marker and clock -void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *bits) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); +void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol) { - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(false); - - int ledcontrol = 1, 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 stt = (arg2 >> 8) & 1; + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - if ( stt ) { - //int fsktype = ( fcHigh == 8 && fcLow == 5) ? 1 : 2; - //fcSTT(&n); - } - - for (i=0; i> 8) & 0xFF; - uint8_t encoding = arg1 & 0xFF; - uint8_t separator = arg2 & 1; - uint8_t invert = (arg2 >> 8) & 1; +void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol) { + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + set_tracing(false); - 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; - for (i=0; i 0 && lo > 0 && (size == 96 || size == 192)){ - // go over previously decoded manchester data and decode into usable tag ID - if (hi2 != 0){ //extra large HID tags 88/192 bits - Dbprintf("TAG ID: %x%08x%08x (%d)", - hi2, - hi, - lo, - (lo >> 1) & 0xFFFF - ); - } else { //standard HID tags 44/96 bits - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - - if (((hi >> 5) & 1) == 1){//if bit 38 is set then < 37 bit format is used - uint32_t lo2 = 0; - lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit - uint8_t idx3 = 1; - while (lo2 > 1){ //find last bit set to 1 (format len bit) - lo2 >>= 1; - idx3++; - } - bitlen = idx3 + 19; - fc = 0; - cardnum = 0; - if (bitlen == 26){ - cardnum = (lo >> 1) & 0xFFFF; - fc = (lo >> 17) & 0xFF; - } - if (bitlen == 37){ - cardnum = (lo >> 1 ) & 0x7FFFF; - fc = ((hi & 0xF) << 12) | (lo >> 20); - } - if (bitlen == 34){ - cardnum = (lo >> 1) & 0xFFFF; - fc = ((hi & 1) << 15) | (lo >> 17); - } - if (bitlen == 35){ - cardnum = (lo >> 1) & 0xFFFFF; - fc = ((hi & 1) << 11)|(lo >> 21); - } - } - else { //if bit 38 is not set then 37 bit format is used - bitlen= 37; - fc = 0; - cardnum = 0; - if (bitlen == 37){ - cardnum = (lo >> 1) & 0x7FFFF; - fc = ((hi & 0xF) << 12) | (lo >> 20); - } - } - Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", - hi, - lo, - (lo >> 1) & 0xFFFF, - bitlen, - fc, - cardnum - ); - } - if (findone){ - *high = hi; - *low = lo; - break; - } - // reset - } - hi2 = hi = lo = idx = 0; - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + DoAcquisition_default(-1, true); + // FSK demodulator + size = 50 * 128 * 2; //big enough to catch 2 sequences of largest format + int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); + if (idx < 0) continue; + + if (idx > 0 && lo > 0 && (size == 96 || size == 192)) { + // go over previously decoded manchester data and decode into usable tag ID + if (hi2 != 0) { //extra large HID tags 88/192 bits + Dbprintf("TAG ID: %x%08x%08x (%d)", + hi2, + hi, + lo, + (lo >> 1) & 0xFFFF + ); + } else { //standard HID tags 44/96 bits + uint8_t bitlen = 0; + uint32_t fac = 0; + uint32_t cardnum = 0; + + if (((hi >> 5) & 1) == 1) { //if bit 38 is set then < 37 bit format is used + uint32_t lo2 = 0; + lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while (lo2 > 1) { //find last bit set to 1 (format len bit) + lo2 >>= 1; + idx3++; + } + bitlen = idx3 + 19; + fac = 0; + cardnum = 0; + if (bitlen == 26) { + cardnum = (lo >> 1) & 0xFFFF; + fac = (lo >> 17) & 0xFF; + } + if (bitlen == 37) { + cardnum = (lo >> 1) & 0x7FFFF; + fac = ((hi & 0xF) << 12) | (lo >> 20); + } + if (bitlen == 34) { + cardnum = (lo >> 1) & 0xFFFF; + fac = ((hi & 1) << 15) | (lo >> 17); + } + if (bitlen == 35) { + cardnum = (lo >> 1) & 0xFFFFF; + fac = ((hi & 1) << 11) | (lo >> 21); + } + } else { //if bit 38 is not set then 37 bit format is used + bitlen = 37; + cardnum = (lo >> 1) & 0x7FFFF; + fac = ((hi & 0xF) << 12) | (lo >> 20); + } + Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + hi, + lo, + (lo >> 1) & 0xFFFF, + bitlen, + fac, + cardnum + ); + } + if (findone) { + *high = hi; + *low = lo; + break; + } + // reset + } + hi2 = hi = lo = idx = 0; + } + 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, uint32_t *high, uint32_t *low, int ledcontrol) { - uint8_t *dest = BigBuf_get_addr(); - - //big enough to catch 2 sequences of largest format - size_t size = 12800; //50 * 128 * 2; + uint8_t *dest = BigBuf_get_addr(); - int idx = 0, dummyIdx = 0; + //big enough to catch 2 sequences of largest format + size_t size = 12800; //50 * 128 * 2; - BigBuf_Clear_keep_EM(); + int dummyIdx = 0; - LFSetupFPGAForADC(95, true); + BigBuf_Clear_keep_EM(); - while (!BUTTON_PRESS() && !usb_poll_validate_length()) { + LFSetupFPGAForADC(95, true); - WDT_HIT(); - if (ledcontrol) LED_A_ON(); + while (!BUTTON_PRESS() && !data_available()) { - DoAcquisition_default(-1, true); - // FSK demodulator + WDT_HIT(); + if (ledcontrol) LED_A_ON(); - idx = detectAWID(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) + DoAcquisition_default(-1, true); + // FSK demodulator - //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); + int idx = detectAWID(dest, &size, &dummyIdx); - size = removeParity(dest, idx+8, 4, 1, 88); - if (size != 66) continue; - // ok valid card found! + 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) - // 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) + //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); - 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(); - *high = rawHi; - *low = rawLo; - break; - } - // reset - idx = 0; - WDT_HIT(); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + 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) + + uint8_t fmtLen = bytebits_to_byte(dest, 8); + if (fmtLen == 26) { + uint32_t fac = bytebits_to_byte(dest + 9, 8); + uint32_t cardnum = bytebits_to_byte(dest + 17, 16); + uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); + Dbprintf("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo); + } else { + uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16); + if (fmtLen > 32) { + uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32); + uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32); + Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); + } else { + uint32_t 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(); + *high = rawHi; + *low = rawLo; + break; + } + WDT_HIT(); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol) { - uint8_t *dest = BigBuf_get_addr(); + 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; + size_t size, idx = 0; + int clk = 0, invert = 0, maxErr = 20; + uint32_t hi = 0; + uint64_t lo = 0; - BigBuf_Clear_keep_EM(); + BigBuf_Clear_keep_EM(); - LFSetupFPGAForADC(95, true); + LFSetupFPGAForADC(95, true); - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { + while (!BUTTON_PRESS() && !data_available()) { - WDT_HIT(); - if (ledcontrol) LED_A_ON(); + 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(); + DoAcquisition_default(-1, true); - if (errCnt < 0) continue; - - errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); - if (errCnt == 1){ - if (size == 128){ - 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)); - } + size = BigBuf_max_traceLen(); + //askdemod and manchester decode + if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format + int errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1); + WDT_HIT(); - if (findone){ - if (ledcontrol) LED_A_OFF(); - *high = hi; - *low = lo; - break; - } - } - WDT_HIT(); - hi = lo = size = idx = 0; - clk = invert = errCnt = 0; - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + if (errCnt > 50) continue; + + errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); + if (errCnt == 1) { + if (size == 128) { + 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 = hi; + *low = lo; + break; + } + } + WDT_HIT(); + hi = lo = size = idx = 0; + clk = invert = 0; + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) { - uint8_t *dest = BigBuf_get_addr(); + uint8_t *dest = BigBuf_get_addr(); - int dummyIdx = 0, idx = 0; - uint32_t code = 0, code2 = 0; - uint8_t version = 0, facilitycode = 0, crc = 0; - uint16_t number = 0, calccrc = 0; + int dummyIdx = 0; + uint32_t code = 0, code2 = 0; + uint8_t version = 0, facilitycode = 0, crc = 0; + uint16_t number = 0, calccrc = 0; - size_t size = BigBuf_max_traceLen(); - - BigBuf_Clear_keep_EM(); - - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(95, true); + size_t size = BigBuf_max_traceLen(); - while (!BUTTON_PRESS() && !usb_poll_validate_length()) { - WDT_HIT(); - if (ledcontrol) LED_A_ON(); + BigBuf_Clear_keep_EM(); - DoAcquisition_default(-1, true); + // Configure to go in 125Khz listen mode + LFSetupFPGAForADC(95, true); - //fskdemod and get start index - WDT_HIT(); - idx = detectIOProx(dest, &size, &dummyIdx); - if (idx < 0) continue; - //valid tag found + while (!BUTTON_PRESS() && !data_available()) { + WDT_HIT(); + if (ledcontrol) LED_A_ON(); - //Index map - //0 10 20 30 40 50 60 - //| | | | | | | - //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 - //----------------------------------------------------------------------------- - //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 checksum 11 - // - //Checksum: - //00000000 0 11110000 1 11100000 1 00000001 1 00000011 1 10110110 1 01110101 11 - //preamble F0 E0 01 03 B6 75 - // How to calc checksum, - // http://www.proxmark.org/forum/viewtopic.php?id=364&p=6 - // F0 + E0 + 01 + 03 + B6 = 28A - // 28A & FF = 8A - // FF - 8A = 75 - // Checksum: 0x75 - //XSF(version)facility:codeone+codetwo - //Handle the data - // if(findone){ //only print binary if we are doing one - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx], dest[idx+1], dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]); - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]); - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]); - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]); - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]); - // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]); - // Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]); - // } - code = bytebits_to_byte(dest+idx, 32); - code2 = bytebits_to_byte(dest+idx+32, 32); - version = bytebits_to_byte(dest+idx+27, 8); //14,4 - facilitycode = bytebits_to_byte(dest+idx+18, 8); - number = (bytebits_to_byte(dest+idx+36, 8) << 8) | (bytebits_to_byte(dest+idx+45, 8)); //36,9 + DoAcquisition_default(-1, true); - crc = bytebits_to_byte(dest+idx+54, 8); - for (uint8_t i=1; i<6; ++i) - calccrc += bytebits_to_byte(dest+idx+9*i, 8); - calccrc &= 0xff; - calccrc = 0xff - calccrc; - - char *crcStr = (crc == calccrc) ? "ok" : "!crc"; + //fskdemod and get start index + WDT_HIT(); + int idx = detectIOProx(dest, &size, &dummyIdx); + if (idx < 0) continue; + //valid tag found - Dbprintf("IO Prox XSF(%02d)%02x:%05d (%08x%08x) [%02x %s]", version, facilitycode, number, code, code2, crc, crcStr); - // if we're only looking for one tag - if (findone){ - if (ledcontrol) LED_A_OFF(); - *high = code; - *low = code2; - break; - } - code = code2 = 0; - version = facilitycode = 0; - number = 0; - idx = 0; + //Index map + //0 10 20 30 40 50 60 + //| | | | | | | + //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23 + //----------------------------------------------------------------------------- + //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 checksum 11 + // + //Checksum: + //00000000 0 11110000 1 11100000 1 00000001 1 00000011 1 10110110 1 01110101 11 + //preamble F0 E0 01 03 B6 75 + // How to calc checksum, + // http://www.proxmark.org/forum/viewtopic.php?id=364&p=6 + // F0 + E0 + 01 + 03 + B6 = 28A + // 28A & FF = 8A + // FF - 8A = 75 + // Checksum: 0x75 + //XSF(version)facility:codeone+codetwo + //Handle the data + // if(findone){ //only print binary if we are doing one + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx], dest[idx+1], dest[idx+2],dest[idx+3],dest[idx+4],dest[idx+5],dest[idx+6],dest[idx+7],dest[idx+8]); + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+9], dest[idx+10],dest[idx+11],dest[idx+12],dest[idx+13],dest[idx+14],dest[idx+15],dest[idx+16],dest[idx+17]); + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+18],dest[idx+19],dest[idx+20],dest[idx+21],dest[idx+22],dest[idx+23],dest[idx+24],dest[idx+25],dest[idx+26]); + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+27],dest[idx+28],dest[idx+29],dest[idx+30],dest[idx+31],dest[idx+32],dest[idx+33],dest[idx+34],dest[idx+35]); + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+36],dest[idx+37],dest[idx+38],dest[idx+39],dest[idx+40],dest[idx+41],dest[idx+42],dest[idx+43],dest[idx+44]); + // Dbprintf("%d%d%d%d%d%d%d%d %d",dest[idx+45],dest[idx+46],dest[idx+47],dest[idx+48],dest[idx+49],dest[idx+50],dest[idx+51],dest[idx+52],dest[idx+53]); + // Dbprintf("%d%d%d%d%d%d%d%d %d%d",dest[idx+54],dest[idx+55],dest[idx+56],dest[idx+57],dest[idx+58],dest[idx+59],dest[idx+60],dest[idx+61],dest[idx+62],dest[idx+63]); + // } + code = bytebits_to_byte(dest + idx, 32); + code2 = bytebits_to_byte(dest + idx + 32, 32); + version = bytebits_to_byte(dest + idx + 27, 8); //14,4 + facilitycode = bytebits_to_byte(dest + idx + 18, 8); + number = (bytebits_to_byte(dest + idx + 36, 8) << 8) | (bytebits_to_byte(dest + idx + 45, 8)); //36,9 - WDT_HIT(); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); + crc = bytebits_to_byte(dest + idx + 54, 8); + for (uint8_t i = 1; i < 6; ++i) + calccrc += bytebits_to_byte(dest + idx + 9 * i, 8); + calccrc &= 0xff; + calccrc = 0xff - calccrc; + + char *crcStr = (crc == calccrc) ? "ok" : "!crc"; + + Dbprintf("IO Prox XSF(%02d)%02x:%05d (%08x%08x) [%02x %s]", version, facilitycode, number, code, code2, crc, crcStr); + // if we're only looking for one tag + if (findone) { + if (ledcontrol) LED_A_OFF(); + *high = code; + *low = code2; + break; + } + code = code2 = 0; + version = facilitycode = 0; + number = 0; + WDT_HIT(); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Stopped"); + if (ledcontrol) LED_A_OFF(); } /*------------------------------ * T5555/T5557/T5567/T5577 routines *------------------------------ - * NOTE: T55x7/T5555 configuration register definitions moved to protocols.h + * NOTE: T55x7/T5555 configuration register definitions moved to protocols.h * * Relevant communication times in microsecond * To compensate antenna falling times shorten the write times * and enlarge the gap ones. - * Q5 tags seems to have issues when these values changes. + * Q5 tags seems to have issues when these values changes. */ void TurnReadLFOn(uint32_t delay) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // measure antenna strength. - //int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); - - // Give it a bit of time for the resonant antenna to settle. - WaitUS(delay); + // measure antenna strength. + //int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); + WaitUS(delay); } void TurnReadLF_off(uint32_t delay) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(delay); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(delay); } // Write one bit to card void T55xxWriteBit(int bit) { - if (!bit) - TurnReadLFOn(WRITE_0); - else - TurnReadLFOn(WRITE_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP); + if (!bit) + TurnReadLFOn(t_config.write_0); + else + TurnReadLFOn(t_config.write_1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(t_config.write_gap); } // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { - LED_A_ON(); - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_keep_EM(); + LED_A_ON(); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_keep_EM(); - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + // make sure tag is fully powered up... + WaitMS(4); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(t_config.start_gap); - // reset tag - op code 00 - T55xxWriteBit(0); - T55xxWriteBit(0); + // reset tag - op code 00 + T55xxWriteBit(0); + T55xxWriteBit(0); - TurnReadLFOn(READ_GAP); + TurnReadLFOn(t_config.read_gap); - // Acquisition - DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); + // 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(); + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + LED_A_OFF(); } // Write one card block in page 0, no lock -void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) { - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - uint32_t i = 0; +void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags) { + LED_A_ON(); + bool pwd_mode = (flags & 0x1); + uint8_t page = (flags & 0x2) >> 1; + bool test_mode = (flags & 0x4) >> 2; + uint32_t i = 0; - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - T55xxWriteBit(testMode ? 0 : 1); - T55xxWriteBit(testMode ? 1 : Page); //Page 0 + // make sure tag is fully powered up... + WaitMS(4); - if (PwdMode){ - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send Lock bit - T55xxWriteBit(0); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(t_config.start_gap); - // Send Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Data & i); + if (test_mode) { + Dbprintf("T55xx writing with %s", _YELLOW_("test mode enabled")); + // undocmented testmode opcode 01 + T55xxWriteBit(0); + T55xxWriteBit(1); + } else { + // std opcode 10 == page 0 + // std opcode 11 == page 1 + T55xxWriteBit(1); + T55xxWriteBit(page); + } - // Send Block number - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); + if (pwd_mode) { + // Send pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(pwd & i); + } + // Send lock bit + T55xxWriteBit(0); - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) + // Send data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(data & i); - // "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); + // Send block number + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(blockno & i); - } 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. + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) - //DoPartialAcquisition(20, true, 12000); - } - - // turn field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); + // "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 (test_mode) { + //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); + + } 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 + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); } // Write one card block in page 0, no lock -void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t arg) { - T55xxWriteBlockExt(Data, Block, Pwd, arg); - cmd_send(CMD_ACK,0,0,0,0,0); +// uses NG format +void T55xxWriteBlock(uint8_t *data) { + t55xx_write_block_t *c = (t55xx_write_block_t *)data; + T55xxWriteBlockExt(c->data, c->blockno, c->pwd, c->flags); + reply_ng(CMD_T55XX_WRITE_BLOCK, PM3_SUCCESS, NULL, 0); } // Read one card block in page [page] -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { - LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_keep_EM(); +void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd) { + LED_A_ON(); + bool regular_readmode = (block == 0xFF); + uint8_t start_wait = 4; + size_t samples = 12000; + uint32_t i; - //make sure block is at max 7 - Block &= 0x7; + if (brute_mem) { + start_wait = 0; + samples = 1024; + } - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Opcode 1[page] - T55xxWriteBit(1); - T55xxWriteBit(Page); //Page 0 + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_keep_EM(); - if (PwdMode){ - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); + //make sure block is at max 7 + block &= 0x7; - // 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 - // 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(); + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + // make sure tag is fully powered up... + WaitMS(start_wait); + + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(t_config.start_gap); + + // Opcode 1[page] + T55xxWriteBit(1); + T55xxWriteBit(page); //Page 0 + + if (pwd_mode) { + // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(pwd & i); + } + // Send a zero bit separation + T55xxWriteBit(0); + + // Send Block number (if direct access mode) + if (!regular_readmode) + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(block & i); + + // 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(150 * 8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, samples, 0); + + // Turn the field off + if (!brute_mem) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_T55XX_READ_BLOCK, PM3_SUCCESS, NULL, 0); + LED_A_OFF(); + } } -void T55xxWakeUp(uint32_t Pwd){ - LED_B_ON(); - uint32_t i = 0; - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - - // Trigger T55x7 Direct Access Mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Opcode 10 - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 +void T55xx_ChkPwds() { - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + DbpString("[+] T55XX Check pwds using flashmemory starting"); - // Turn and leave field on to let the begin repeating transmission - TurnReadLFOn(20*1000); + uint8_t ret = 0; + // First get baseline and setup LF mode. + // tends to mess up BigBuf + uint8_t *buf = BigBuf_get_addr(); + + uint32_t b1, baseline = 0; + + // collect baseline for failed attempt + uint8_t x = 32; + while (x--) { + b1 = 0; + +// T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd) + T55xxReadBlock(0, 0, true, 1, 0); + for (uint16_t j = 0; j < 1024; ++j) + b1 += buf[j]; + + b1 *= b1; + b1 >>= 8; + baseline += b1; + } + + baseline >>= 5; + Dbprintf("[=] Baseline determined [%u]", baseline); + + uint8_t *pwds = BigBuf_get_EM_addr(); + uint16_t pwdCount = 0; + uint32_t candidate = 0; + +#ifdef WITH_FLASH + BigBuf_Clear_EM(); + uint16_t isok = 0; + uint8_t counter[2] = {0x00, 0x00}; + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET, counter, sizeof(counter)); + if (isok != sizeof(counter)) + goto OUT; + + pwdCount = counter[1] << 8 | counter[0]; + + if (pwdCount == 0 || pwdCount == 0xFFFF) + goto OUT; + + isok = Flash_ReadData(DEFAULT_T55XX_KEYS_OFFSET + 2, pwds, pwdCount * 4); + if (isok != pwdCount * 4) + goto OUT; + + Dbprintf("[=] Password dictionary count %d ", pwdCount); +#endif + + uint32_t pwd = 0, curr = 0, prev = 0; + for (uint16_t i = 0; i < pwdCount; ++i) { + + if (BUTTON_PRESS() && !data_available()) { + goto OUT; + } + + pwd = bytes_to_num(pwds + i * 4, 4); + + T55xxReadBlock(0, true, true, 0, pwd); + + // calc mean of BigBuf 1024 samples. + uint32_t sum = 0; + for (uint16_t j = 0; j < 1024; ++j) { + sum += buf[j]; + } + + sum *= sum; + sum >>= 8; + + int32_t tmp = (sum - baseline); + curr = ABS(tmp); + + Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr); + + if (curr > prev) { + + + Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd); + candidate = pwd; + prev = curr; + } + } + + if (candidate) + ret = 1; + +OUT: + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_mix(CMD_ACK, ret, candidate, 0, 0, 0); + LEDsoff(); +} + +void T55xxWakeUp(uint32_t Pwd) { + LED_B_ON(); + uint32_t i = 0; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + // make sure tag is fully powered up... + WaitMS(4); + + // Trigger T55x7 Direct Access Mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(t_config.start_gap); + + // Opcode 10 + T55xxWriteBit(1); + T55xxWriteBit(0); //Page 0 + + // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + + // Turn and leave field on to let the begin repeating transmission + TurnReadLFOn(20 * 1000); } /*-------------- 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--) - T55xxWriteBlockExt(blockdata[i-1], i-1, 0, 0); + // write last block first and config block last (if included) + for (uint8_t i = numblocks + startblock; i > startblock; i--) + T55xxWriteBlockExt(blockdata[i - 1], i - 1, 0, 0); } // Copy HID id to card and setup block 0 config void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { - uint32_t data[] = {0,0,0,0,0,0,0}; - uint8_t last_block = 0; + 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 (1D) & long format identifier (9E manchester encoded) - data[1] = 0x1D96A900 | (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] = 0x1D000000 | (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; + 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 (1D) & long format identifier (9E manchester encoded) + data[1] = 0x1D96A900 | (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] = 0x1D000000 | (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] = T5555_SET_BITRATE(50) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | last_block << T5555_MAXBLOCK_SHIFT; + //TODO add selection of chip for Q5 or T55x7 + // data[0] = T5555_SET_BITRATE(50) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | last_block << T5555_MAXBLOCK_SHIFT; - LED_D_ON(); - WriteT55xx(data, 0, last_block+1); - LED_D_OFF(); + LED_D_ON(); + WriteT55xx(data, 0, last_block + 1); + LED_D_OFF(); } 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] = T5555_SET_BITRATE(64) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 2 << T5555_MAXBLOCK_SHIFT; + 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] = T5555_SET_BITRATE(64) | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | 2 << T5555_MAXBLOCK_SHIFT; - LED_D_ON(); - // Program the data blocks for supplied ID - // and the block 0 config - WriteT55xx(data, 0, 3); - LED_D_OFF(); + LED_D_ON(); + // Program the data blocks for supplied ID + // and the block 0 config + WriteT55xx(data, 0, 3); + LED_D_OFF(); } // Clone Indala 64-bit tag by UID to T55x7 void CopyIndala64toT55x7(uint32_t hi, uint32_t lo) { - //Program the 2 data blocks for supplied 64bit UID - // and the Config for Indala 64 format (RF/32;PSK2 with RF/2;Maxblock=2) - uint32_t data[] = { T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (2 << T55x7_MAXBLOCK_SHIFT), hi, lo}; - //TODO add selection of chip for Q5 or T55x7 - // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 2 << T5555_MAXBLOCK_SHIFT; - - WriteT55xx(data, 0, 3); - //Alternative config for Indala (Extended mode;RF/32;PSK2 with RF/2;Maxblock=2;Inverse data) - // T5567WriteBlock(0x603E1042,0); + //Program the 2 data blocks for supplied 64bit UID + // and the Config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2) + uint32_t data[] = { T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT), hi, lo}; + //TODO add selection of chip for Q5 or T55x7 + // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; + LED_D_ON(); + WriteT55xx(data, 0, 3); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) + // T5567WriteBlock(0x603E1042,0); + LED_D_OFF(); } // Clone Indala 224-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) { - //Program the 7 data blocks for supplied 224bit UID - uint32_t data[] = {0, uid1, uid2, uid3, uid4, uid5, uid6, uid7}; - // and the block 0 for Indala224 format - //Config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) - data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); - //TODO add selection of chip for Q5 or T55x7 - // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 7 << T5555_MAXBLOCK_SHIFT; - WriteT55xx(data, 0, 8); - //Alternative config for Indala (Extended mode;RF/32;PSK2 with RF/2;Maxblock=7;Inverse data) - // T5567WriteBlock(0x603E10E2,0); + //Program the 7 data blocks for supplied 224bit UID + uint32_t data[] = {0, uid1, uid2, uid3, uid4, uid5, uid6, uid7}; + // and the block 0 for Indala224 format + //Config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) + data[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); + //TODO add selection of chip for Q5 or T55x7 + // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 7 << T5555_MAXBLOCK_SHIFT; + LED_D_ON(); + WriteT55xx(data, 0, 8); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) + // T5567WriteBlock(0x603E10E2,0); + LED_D_OFF(); } // clone viking tag to T55xx void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5) { - uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), block1, block2}; - if (Q5) data[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT; - // Program the data blocks for supplied ID and the block 0 config - WriteT55xx(data, 0, 3); - LED_D_OFF(); - cmd_send(CMD_ACK,0,0,0,0,0); + uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), block1, block2}; + if (Q5) data[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_MANCHESTER | 2 << T5555_MAXBLOCK_SHIFT; + // Program the data blocks for supplied ID and the block 0 config + WriteT55xx(data, 0, 3); + LED_D_OFF(); + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); } // Define 9bit header for EM410x tags -#define EM410X_HEADER 0x1FF -#define EM410X_ID_LENGTH 40 +#define EM410X_HEADER 0x1FF +#define EM410X_ID_LENGTH 40 void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { - int i, id_bit; - uint64_t id = EM410X_HEADER; - uint64_t rev_id = 0; // reversed ID - int c_parity[4]; // column parity - int r_parity = 0; // row parity - uint32_t clock = 0; + int i; + uint64_t id = EM410X_HEADER; + uint64_t rev_id = 0; // reversed ID + int c_parity[4]; // column parity + int r_parity = 0; // row parity + uint32_t clock = 0; - // Reverse ID bits given as parameter (for simpler operations) - for (i = 0; i < EM410X_ID_LENGTH; ++i) { - if (i < 32) { - rev_id = (rev_id << 1) | (id_lo & 1); - id_lo >>= 1; - } else { - rev_id = (rev_id << 1) | (id_hi & 1); - id_hi >>= 1; - } - } + // Reverse ID bits given as parameter (for simpler operations) + for (i = 0; i < EM410X_ID_LENGTH; ++i) { + if (i < 32) { + rev_id = (rev_id << 1) | (id_lo & 1); + id_lo >>= 1; + } else { + rev_id = (rev_id << 1) | (id_hi & 1); + id_hi >>= 1; + } + } - for (i = 0; i < EM410X_ID_LENGTH; ++i) { - id_bit = rev_id & 1; + for (i = 0; i < EM410X_ID_LENGTH; ++i) { + int id_bit = rev_id & 1; - if (i % 4 == 0) { - // Don't write row parity bit at start of parsing - if (i) - id = (id << 1) | r_parity; - // Start counting parity for new row - r_parity = id_bit; - } else { - // Count row parity - r_parity ^= id_bit; - } + if (i % 4 == 0) { + // Don't write row parity bit at start of parsing + if (i) + id = (id << 1) | r_parity; + // Start counting parity for new row + r_parity = id_bit; + } else { + // Count row parity + r_parity ^= id_bit; + } - // First elements in column? - if (i < 4) - // Fill out first elements - c_parity[i] = id_bit; - else - // Count column parity - c_parity[i % 4] ^= id_bit; + // First elements in column? + if (i < 4) + // Fill out first elements + c_parity[i] = id_bit; + else + // Count column parity + c_parity[i % 4] ^= id_bit; - // Insert ID bit - id = (id << 1) | id_bit; - rev_id >>= 1; - } + // Insert ID bit + id = (id << 1) | id_bit; + rev_id >>= 1; + } - // Insert parity bit of last row - id = (id << 1) | r_parity; + // Insert parity bit of last row + id = (id << 1) | r_parity; - // Fill out column parity at the end of tag - for (i = 0; i < 4; ++i) - id = (id << 1) | c_parity[i]; + // Fill out column parity at the end of tag + for (i = 0; i < 4; ++i) + id = (id << 1) | c_parity[i]; - // Add stop bit - id <<= 1; + // Add stop bit + id <<= 1; - Dbprintf("Started writing %s tag ...", card ? "T55x7":"T5555"); - LED_D_ON(); + Dbprintf("Started writing %s tag ...", card ? "T55x7" : "T5555"); + LED_D_ON(); - // Write EM410x ID - uint32_t data[] = {0, (uint32_t)(id>>32), (uint32_t)(id & 0xFFFFFFFF)}; + // Write EM410x ID + uint32_t data[] = {0, (uint32_t)(id >> 32), (uint32_t)(id & 0xFFFFFFFF)}; - 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; - } - 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); + 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; + } + 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); + } - LED_D_OFF(); - Dbprintf("Tag %s written with 0x%08x%08x\n", - card ? "T55x7":"T5555", - (uint32_t)(id >> 32), - (uint32_t)id); + WriteT55xx(data, 0, 3); + + LED_D_OFF(); + Dbprintf("Tag %s written with 0x%08x%08x\n", + card ? "T55x7" : "T5555", + (uint32_t)(id >> 32), + (uint32_t)id); } //----------------------------------- // EM4469 / EM4305 routines //----------------------------------- -// Below given command set. +// Below given command set. // Commands are including the even parity, binary mirrored -#define FWD_CMD_LOGIN 0xC +#define FWD_CMD_LOGIN 0xC #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 #define FWD_CMD_DISABLE 0x5 uint8_t forwardLink_data[64]; //array of forwarded bits -uint8_t * forward_ptr; //ptr for forward message preparation +uint8_t *forward_ptr; //ptr for forward message preparation uint8_t fwd_bit_sz; //forwardlink bit counter -uint8_t * fwd_write_ptr; //forwardlink bit pointer +uint8_t *fwd_write_ptr; //forwardlink bit pointer //==================================================================== // prepares command bits @@ -1675,82 +1878,81 @@ uint8_t * fwd_write_ptr; //forwardlink bit pointer // 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) +// 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 -uint8_t Prepare_Cmd( uint8_t cmd ) { +uint8_t Prepare_Cmd(uint8_t cmd) { - *forward_ptr++ = 0; //start bit - *forward_ptr++ = 0; //second pause for 4050 code + *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; + *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 + return 6; //return number of emited bits } //==================================================================== // prepares address bits // see EM4469 spec //==================================================================== -uint8_t Prepare_Addr( uint8_t addr ) { +uint8_t Prepare_Addr(uint8_t addr) { - register uint8_t line_parity; + 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; - } + 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); + *forward_ptr++ = (line_parity & 1); - return 7; //return number of emited bits + 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) { +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; + register uint8_t column_parity; + register uint8_t i, j; + register uint16_t data; - data = data_low; - column_parity = 0; + 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 (i = 0; i < 4; i++) { + register uint8_t 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; + for (j = 0; j < 8; j++) { + *forward_ptr++ = column_parity; + column_parity >>= 1; + } + *forward_ptr = 0; - return 45; //return number of emited bits + return 45; //return number of emited bits } //==================================================================== @@ -1763,114 +1965,110 @@ void SendForward(uint8_t fwd_bit_count) { // iceman, 21.3us increments for the USclock verification. // 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead // 32FC * 8us == 256us / 21.3 == 12.018 steps. ok -// 16FC * 8us == 128us / 21.3 == 6.009 steps. ok +// 16FC * 8us == 128us / 21.3 == 6.009 steps. ok #ifndef EM_START_GAP #define EM_START_GAP 55*8 #endif - fwd_write_ptr = forwardLink_data; - fwd_bit_sz = 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++; - - TurnReadLF_off(EM_START_GAP); - TurnReadLFOn(18*8); + // Set up FPGA, 125kHz or 95 divisor + LFSetupFPGAForADC(95, true); - // now start writting with bitbanging the antenna. - while(fwd_bit_sz-- > 0) { //prepare next bit modulation - if(((*fwd_write_ptr++) & 1) == 1) { - WaitUS(32*8); - } else { - TurnReadLF_off(23*8); - TurnReadLFOn(18*8); - } - } + // force 1st mod pulse (start gap must be longer for 4305) + fwd_bit_sz--; //prepare next bit modulation + fwd_write_ptr++; + + TurnReadLF_off(EM_START_GAP); + TurnReadLFOn(18 * 8); + + // now start writting with bitbanging the antenna. + while (fwd_bit_sz-- > 0) { //prepare next bit modulation + if (((*fwd_write_ptr++) & 1) == 1) { + WaitUS(32 * 8); + } else { + TurnReadLF_off(23 * 8); + TurnReadLFOn(18 * 8); + } + } } void EM4xLogin(uint32_t pwd) { - uint8_t len; - forward_ptr = forwardLink_data; - len = Prepare_Cmd( FWD_CMD_LOGIN ); - len += Prepare_Data( pwd & 0xFFFF, pwd >> 16 ); - SendForward(len); - //WaitUS(20); // no wait for login command. - // should receive - // 0000 1010 ok. - // 0000 0001 fail + uint8_t len; + forward_ptr = forwardLink_data; + len = Prepare_Cmd(FWD_CMD_LOGIN); + len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); + SendForward(len); + //WaitUS(20); // no wait for login command. + // should receive + // 0000 1010 ok. + // 0000 0001 fail } void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { - LED_A_ON(); - uint8_t len; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - StartTicks(); - /* should we read answer from Logincommand? - * - * should receive - * 0000 1010 ok. - * 0000 0001 fail - **/ - if (usepwd) EM4xLogin(pwd); + LED_A_ON(); + uint8_t len; - forward_ptr = forwardLink_data; - len = Prepare_Cmd( FWD_CMD_READ ); - len += Prepare_Addr( addr ); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); - SendForward(len); + StartTicks(); + /* should we read answer from Logincommand? + * + * should receive + * 0000 1010 ok. + * 0000 0001 fail + **/ + if (usepwd) EM4xLogin(pwd); - WaitUS(400); + forward_ptr = forwardLink_data; + len = Prepare_Cmd(FWD_CMD_READ); + len += Prepare_Addr(addr); - DoPartialAcquisition(20, true, 6000, 1000); + SendForward(len); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); + WaitUS(400); + + DoPartialAcquisition(20, true, 6000, 1000); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_EM4X_READ_WORD, PM3_SUCCESS, NULL, 0); + LED_A_OFF(); } -void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd) { +void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { - LED_A_ON(); - - bool usePwd = (flag & 0xF); - uint8_t addr = (flag >> 8) & 0xFF; - uint8_t len; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - StartTicks(); - /* should we read answer from Logincommand? - * - * should receive - * 0000 1010 ok. - * 0000 0001 fail - **/ - if (usePwd) EM4xLogin(pwd); + LED_A_ON(); + uint8_t len; - forward_ptr = forwardLink_data; - len = Prepare_Cmd( FWD_CMD_WRITE ); - len += Prepare_Addr( addr ); - len += Prepare_Data( data & 0xFFFF, data >> 16 ); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + StartTicks(); + /* should we read answer from Logincommand? + * + * should receive + * 0000 1010 ok. + * 0000 0001 fail + **/ + if (usepwd) EM4xLogin(pwd); - SendForward(len); + forward_ptr = forwardLink_data; + len = Prepare_Cmd(FWD_CMD_WRITE); + len += Prepare_Addr(addr); + len += Prepare_Data(data & 0xFFFF, data >> 16); - //Wait 20ms for write to complete? - WaitMS(7); + SendForward(len); - //Capture response if one exists - DoPartialAcquisition(20, true, 6000, 1000); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); + //Wait 20ms for write to complete? + WaitMS(7); + + DoPartialAcquisition(20, true, 6000, 1000); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_EM4X_WRITE_WORD, PM3_SUCCESS, NULL, 0); + LED_A_OFF(); } /* @@ -1889,50 +2087,42 @@ This triggers a COTAG tag to response */ void Cotag(uint32_t arg0) { #ifndef OFF -# define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } +# define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); } #endif #ifndef ON # define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } #endif - uint8_t rawsignal = arg0 & 0xF; + uint8_t rawsignal = arg0 & 0xF; - LED_A_ON(); + 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); + LFSetupFPGAForADC(89, true); - // 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(); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); - // start clock - 1.5ticks is 1us - StartTicks(); - - //send COTAG start pulse - ON(740) OFF - ON(3330) OFF - ON(740) OFF - ON(1000) + //send COTAG start pulse + ON(740) OFF(2035) + ON(3330) OFF(2035) + ON(740) OFF(2035) + 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); - LEDsoff(); + 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 + reply_mix(CMD_ACK, 0, 0, 0, 0, 0); + LEDsoff(); } /* diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index c419d5781..c5a075e7a 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -10,26 +10,26 @@ /* Default LF config is set to: - decimation = 1 (we keep 1 out of 1 samples) - bits_per_sample = 8 - averaging = YES - divisor = 95 (125khz) - trigger_threshold = 0 - */ + decimation = 1 (we keep 1 out of 1 samples) + bits_per_sample = 8 + averaging = YES + divisor = 95 (125khz) + trigger_threshold = 0 + */ sample_config config = { 1, 8, 1, 95, 0 } ; void printConfig() { - Dbprintf("LF Sampling config"); - Dbprintf(" [q] divisor.............%d (%d KHz)", config.divisor, 12000 / (config.divisor+1)); - Dbprintf(" [b] bps.................%d", config.bits_per_sample); - Dbprintf(" [d] decimation..........%d", config.decimation); - Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No"); - Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold); + DbpString(_BLUE_("LF Sampling config")); + Dbprintf(" [q] divisor.............%d ( "_GREEN_("%d kHz")")", config.divisor, 12000 / (config.divisor + 1)); + Dbprintf(" [b] bps.................%d", config.bits_per_sample); + Dbprintf(" [d] decimation..........%d", config.decimation); + Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No"); + Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold); } /** * Called from the USB-handler to set the sampling configuration - * The sampling config is used for std reading and snooping. + * The sampling config is used for std reading and sniffing. * * Other functions may read samples and ignore the sampling config, * such as functions to read the UID from a prox tag or similar. @@ -39,25 +39,25 @@ void printConfig() { * @param sc */ void setSamplingConfig(sample_config *sc) { - if(sc->divisor != 0) config.divisor = sc->divisor; - if(sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; - if(sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; - - config.decimation = (sc->decimation != 0) ? sc->decimation : 1; - config.averaging = sc->averaging; - if(config.bits_per_sample > 8) config.bits_per_sample = 8; + if (sc->divisor != 0) config.divisor = sc->divisor; + if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; + if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; - printConfig(); + config.decimation = (sc->decimation != 0) ? sc->decimation : 1; + config.averaging = sc->averaging; + if (config.bits_per_sample > 8) config.bits_per_sample = 8; + + printConfig(); } -sample_config* getSamplingConfig() { - return &config; +sample_config *getSamplingConfig() { + return &config; } struct BitstreamOut { - uint8_t * buffer; - uint32_t numbits; - uint32_t position; + uint8_t *buffer; + uint32_t numbits; + uint32_t position; }; /** @@ -65,40 +65,40 @@ struct BitstreamOut { * @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++; +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 +* @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); + 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)); + 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); - // 50ms 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(); - // start a 1.5ticks is 1us - StartTicks(); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // 50ms 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(); + // start a 1.5ticks is 1us + StartTicks(); } /** @@ -117,96 +117,109 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) { * @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, uint32_t cancel_after) { - //bigbuf, to hold the aquired raw data signal - uint8_t *dest = BigBuf_get_addr(); + + uint8_t *dest = BigBuf_get_addr(); bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); + if (bits_per_sample < 1) bits_per_sample = 1; + if (bits_per_sample > 8) bits_per_sample = 8; - if (bits_per_sample < 1) bits_per_sample = 1; - if (bits_per_sample > 8) bits_per_sample = 8; + if (decimation < 1) decimation = 1; - 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; - // 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; - - 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; - sample_total_numbers++; + // 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; + + uint16_t checker = 0; + + while (true) { + if ( checker == 1000 ) { + if (BUTTON_PRESS() || data_available()) + break; + else + checker = 0; + } else { + ++checker; + } + + WDT_HIT(); - if (averaging) - sample_sum += sample; + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - //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; - } - } - } + // Testpoint 8 (TP8) can be used to trigger oscilliscope + LED_D_OFF(); - 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]); - } - - // Ensure that noise check is performed for any device-side processing - justNoise(dest, bufsize); - - return data.numbits; + // 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; + 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; + + // Get the return value correct + data.numbits = sample_total_saved << 3; + 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); + + if ((data.numbits >> 3) + 1 >= bufsize) break; + } + } + } + + if (!silent) { + Dbprintf("Done, saved " _YELLOW_("%d")"out of " _YELLOW_("%d")"seen samples at " _YELLOW_("%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]); + } + + // Ensure that DC offset removal and noise check is performed for any device-side processing + removeSignalOffset(dest, bufsize); + computeSignalProperties(dest, bufsize); + + return data.numbits; } /** * @brief Does sample acquisition, ignoring the config values set in the sample_config. @@ -217,48 +230,46 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag * @return number of bits sampled */ uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { - return DoAcquisition(1, 8, 0,trigger_threshold, silent, 0, 0); + return DoAcquisition(1, 8, 0, trigger_threshold, silent, 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); +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); } uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after) { - return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after); + return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after); } uint32_t ReadLF(bool activeField, bool silent, int sample_size) { - if (!silent) - printConfig(); - LFSetupFPGAForADC(config.divisor, activeField); - return DoAcquisition_config(silent, sample_size); + if (!silent) + printConfig(); + LFSetupFPGAForADC(config.divisor, activeField); + uint32_t ret = DoAcquisition_config(silent, sample_size); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return ret; } /** * 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) { - BigBuf_Clear_ext(false); - uint32_t ret = ReadLF(true, printCfg, sample_size); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - return ret; +uint32_t SampleLF(bool silent, int sample_size) { + BigBuf_Clear_ext(false); + return ReadLF(true, silent, sample_size); } /** -* Initializes the FPGA for snoop-mode (field off), and acquires the samples. +* Initializes the FPGA for sniffer-mode (field off), and acquires the samples. * @return number of bits sampled **/ -uint32_t SnoopLF() { - BigBuf_Clear_ext(false); - uint32_t ret = ReadLF(false, true, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - return ret; +uint32_t SniffLF() { + BigBuf_Clear_ext(false); + return ReadLF(false, true, 0); } /** @@ -267,63 +278,72 @@ uint32_t SnoopLF() { **/ void doT55x7Acquisition(size_t sample_size) { - #define T55xx_READ_UPPER_THRESHOLD 128+60 // 60 grph - #define T55xx_READ_LOWER_THRESHOLD 128-60 // -60 grph - #define T55xx_READ_TOL 5 - - uint8_t *dest = BigBuf_get_addr(); - uint16_t bufsize = BigBuf_max_traceLen(); - - if ( bufsize > sample_size ) - bufsize = sample_size; +#define T55xx_READ_UPPER_THRESHOLD 128+60 // 60 grph +#define T55xx_READ_LOWER_THRESHOLD 128-60 // -60 grph +#define T55xx_READ_TOL 5 - uint8_t curSample = 0, lastSample = 0; - uint16_t i = 0, skipCnt = 0; - bool startFound = false; - bool highFound = false; - bool lowFound = false; - - while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; //43 - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - - // skip until the first high sample above threshold - if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) { - //if (curSample > lastSample) - // lastSample = curSample; - highFound = true; - } else if (!highFound) { - skipCnt++; - continue; - } - // skip until the first low sample below threshold - if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) { - //if (curSample > lastSample) - lastSample = curSample; - lowFound = true; - } else if (!lowFound) { - skipCnt++; - continue; - } + uint8_t *dest = BigBuf_get_addr(); + uint16_t bufsize = BigBuf_max_traceLen(); - // skip until first high samples begin to change - if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL){ - // if just found start - recover last sample - if (!startFound) { - dest[i++] = lastSample; - startFound = true; - } - // collect samples - dest[i++] = curSample; - } - } - } + if (bufsize > sample_size) + bufsize = sample_size; + + uint8_t curSample, lastSample = 0; + uint16_t i = 0, skipCnt = 0; + bool startFound = false; + bool highFound = false; + bool lowFound = false; + + uint16_t checker = 0; + + while ( skipCnt < 1000 && (i < bufsize)) { + if ( checker == 1000 ) { + if (BUTTON_PRESS() || data_available()) + break; + else + checker = 0; + } else { + ++checker; + } + + WDT_HIT(); + + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + LED_D_OFF(); + + // skip until the first high sample above threshold + if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) { + //if (curSample > lastSample) + // lastSample = curSample; + highFound = true; + } else if (!highFound) { + skipCnt++; + continue; + } + // skip until the first low sample below threshold + if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) { + //if (curSample > lastSample) + lastSample = curSample; + lowFound = true; + } else if (!lowFound) { + skipCnt++; + continue; + } + + // skip until first high samples begin to change + if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) { + // if just found start - recover last sample + if (!startFound) { + dest[i++] = lastSample; + startFound = true; + } + // collect samples + dest[i++] = curSample; + } + } + } } /** * acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384 @@ -339,125 +359,134 @@ void doT55x7Acquisition(size_t sample_size) { #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; + uint8_t *dest = BigBuf_get_addr(); + uint16_t bufsize = BigBuf_max_traceLen(); - dest[0] = 0; - uint8_t sample = 0, firsthigh = 0, firstlow = 0; - uint16_t i = 0; - uint16_t noise_counter = 0; - - while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < 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; - } + if (bufsize > sample_size) + bufsize = sample_size; - ++i; - - if ( sample > COTAG_ONE_THRESHOLD) - dest[i] = 255; - else if ( sample < COTAG_ZERO_THRESHOLD) - dest[i] = 0; - else - dest[i] = dest[i-1]; - } - } + dest[0] = 0; + uint8_t sample, firsthigh = 0, firstlow = 0; + uint16_t i = 0; + uint16_t noise_counter = 0; + + uint16_t checker = 0; + + while ((i < bufsize) && (noise_counter < (COTAG_T1 << 1))) { + if ( checker == 1000 ) { + if (BUTTON_PRESS() || data_available()) + break; + else + checker = 0; + } else { + ++checker; + } + + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + // 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; + } + + ++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; + uint8_t *dest = BigBuf_get_addr(); + uint16_t bufsize = BigBuf_max_traceLen(); - 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; + if (bufsize > COTAG_BITS) + bufsize = COTAG_BITS; - 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; - } + dest[0] = 0; + uint8_t sample, firsthigh = 0, firstlow = 0; + uint16_t sample_counter = 0, period = 0; + uint8_t curr = 0, prev = 0; + uint16_t noise_counter = 0; + uint16_t checker = 0; + + while ((sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1))) { + if ( checker == 1000 ) { + if (BUTTON_PRESS() || data_available()) + break; + else + checker = 0; + } else { + ++checker; + } - // full T1 periods, - if ( period > 0 ) { - --period; - continue; - } - - dest[sample_counter] = curr; - ++sample_counter; - period = COTAG_T1; - } - } - return sample_counter; -} \ No newline at end of file + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + // 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 index aadf0a822..e3c7a0b4d 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -5,8 +5,8 @@ #include "apps.h" #include "util.h" #include "string.h" -#include "usb_cdc.h" // for usb_poll_validate_length -#include "ticks.h" // for StartTicks +#include "usb_cdc.h" // for usb_poll_validate_length +#include "ticks.h" // for StartTicks typedef struct BitstreamOut BitstreamOut; @@ -30,10 +30,10 @@ void doT55x7Acquisition(size_t sample_size); uint32_t SampleLF(bool silent, int sample_size); /** -* Initializes the FPGA for snoop-mode (field off), and acquires the samples. +* Initializes the FPGA for sniff-mode (field off), and acquires the samples. * @return number of bits sampled **/ -uint32_t SnoopLF(); +uint32_t SniffLF(); // adds sample size to default options uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after); @@ -59,15 +59,15 @@ 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 +* @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. + * The sampling config is used for std reading and sniffing. * * Other functions may read samples and ignore the sampling config, * such as functions to read the UID from a prox tag or similar. @@ -78,7 +78,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field); */ void setSamplingConfig(sample_config *sc); -sample_config * getSamplingConfig(); +sample_config *getSamplingConfig(); void printConfig(); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index fcfe99134..26b6583fc 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1,1998 +1,2118 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011, 2012 -// Gerhard de Koning Gans - May 2008 -// Hagen Fritsch - June 2010 -// Midnitesnake - Dec 2013 -// Andy Davies - Apr 2014 -// Iceman - May 2014,2015,2016 -// -// 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 A. -//----------------------------------------------------------------------------- - -#include "mifarecmd.h" -#include - -#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT -# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation) -#endif -#ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME -# define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication -#endif - -// send an incomplete dummy response in order to trigger the card's authentication failure timeout -#ifndef CHK_TIMEOUT -# define CHK_TIMEOUT() { \ - ReaderTransmit(&dummy_answer, 1, NULL); \ - uint32_t timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT; \ - while (GetCountSspClk() < timeout) {}; \ - } -#endif - -static uint8_t dummy_answer = 0; - -//----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. -// read block -//----------------------------------------------------------------------------- -void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // 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] = {0x00}; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - LED_A_ON(); - 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"); - break; - }; - - 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"); - break; - }; - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - crypto1_destroy(pcs); - - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); - LED_B_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ - - bool turnOffField = (arg0 == 1); - - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - 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); - LEDsoff(); - } - cmd_send(CMD_ACK,1,0,0,0,0); -} - -// Arg0 = BlockNo, -// Arg1 = UsePwd bool -// datain = PWD bytes, -void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) -{ - uint8_t blockNo = arg0; - byte_t dataout[16] = {0x00}; - bool useKey = (arg1 == 1); //UL_C - bool usePwd = (arg1 == 2); //UL_EV1/NTAG - - LEDsoff(); - LED_A_ON(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - 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; - } - - cmd_send(CMD_ACK,1,0,0,dataout,16); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -//----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. -// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) -//----------------------------------------------------------------------------- -void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t sectorNo = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - ui64Key = bytes_to_num(datain, 6); - - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16 * 16]; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - LED_A_ON(); - 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)) { - 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); - break; - } - } - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - } - - if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); - - crypto1_destroy(pcs); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo)); - LED_B_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -// 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) -{ - LEDsoff(); - LED_A_ON(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - // 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_EXTENDED) Dbprintf("Blocks read %d", countblocks); - - countblocks *= 4; - - cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - BigBuf_free(); - set_tracing(false); -} - -//----------------------------------------------------------------------------- -// Select, Authenticate, Write a MIFARE tag. -// read block -//----------------------------------------------------------------------------- -void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - byte_t blockdata[16] = {0x00}; - - ui64Key = bytes_to_num(datain, 6); - memcpy(blockdata, datain + 10, 16); - - // variables - byte_t isOK = 0; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - LED_A_ON(); - 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"); - break; - }; - - 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"); - break; - }; - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - crypto1_destroy(pcs); - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - cmd_send(CMD_ACK,isOK,0,0,0,0); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -/* // 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(); - set_tracing(true); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { - 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"); - - cmd_send(CMD_ACK,1,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - 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(); - set_tracing(true); - - 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"); - - cmd_send(CMD_ACK,1,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -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(); - set_tracing(true); - - 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; - }; - - cmd_send(CMD_ACK,1,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -// 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; -} - -void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) { - - uint8_t uid[10] = {0x00}; - uint8_t answer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t par[1] = {0x00}; - uint8_t buf[USB_CMD_DATA_SIZE] = {0x00}; - uint32_t cuid = 0; - int16_t isOK = 0; - uint16_t num_nonces = 0; - uint8_t cascade_levels = 0; - uint8_t blockNo = arg0 & 0xff; - uint8_t keyType = (arg0 >> 8) & 0xff; - bool initialize = flags & 0x0001; - bool field_off = flags & 0x0004; - bool have_uid = false; - - LED_A_ON(); - LED_C_OFF(); - - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - if (initialize) - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_C_ON(); - - for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE-4; i += 4 ) { - - // 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_fast_select_card(uid, cascade_levels)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); - continue; - } - } - - // Transmit MIFARE_CLASSIC_AUTH - uint8_t dcmd[4] = {0x60 + (keyType & 0x01), blockNo, 0x00, 0x00}; - AddCrc14A(dcmd, 2); - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, par); - - // wait for the card to become ready again - CHK_TIMEOUT(); - - if (len != 4) { - if (MF_DBGLEVEL >= 2) Dbprintf("AcquireNonces: Auth1 error"); - continue; - } - - num_nonces++; - - // Save the tag nonce (nt) - buf[i] = answer[0]; - buf[i+1] = answer[1]; - buf[i+2] = answer[2]; - buf[i+3] = answer[3]; - } - - LED_C_OFF(); - LED_B_ON(); - cmd_send(CMD_ACK, isOK, cuid, num_nonces-1, buf, sizeof(buf)); - LED_B_OFF(); - - if (MF_DBGLEVEL >= 3) DbpString("AcquireNonces finished"); - - if (field_off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); - } -} - -//----------------------------------------------------------------------------- -// 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) { - - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - uint8_t uid[10] = {0x00}; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t par_enc[1] = {0x00}; - uint8_t buf[USB_CMD_DATA_SIZE] = {0x00}; - - uint64_t ui64Key = bytes_to_num(datain, 6); - uint32_t cuid = 0; - int16_t isOK = 0; - uint16_t num_nonces = 0; - uint8_t nt_par_enc = 0; - uint8_t cascade_levels = 0; - uint8_t blockNo = arg0 & 0xff; - uint8_t keyType = (arg0 >> 8) & 0xff; - uint8_t targetBlockNo = arg1 & 0xff; - uint8_t targetKeyType = (arg1 >> 8) & 0xff; - bool initialize = flags & 0x0001; - bool slow = flags & 0x0002; - bool field_off = flags & 0x0004; - bool have_uid = false; - - LED_A_ON(); - LED_C_OFF(); - - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(false); - - if (initialize) - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - LED_C_ON(); - - 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_fast_select_card(uid, cascade_levels)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); - continue; - } - } - - if (slow) - SpinDelayUs(HARDNESTED_PRE_AUTHENTICATION_LEADTIME); - - uint32_t nt1; - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, 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); - - // wait for the card to become ready again - CHK_TIMEOUT(); - - if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); - continue; - } - - 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; - } - } - - LED_C_OFF(); - crypto1_destroy(pcs); - LED_B_ON(); - cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); - LED_B_OFF(); - - if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); - - if (field_off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); - } -} - - -//----------------------------------------------------------------------------- -// 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; - uint8_t targetKeyType = (arg1 >> 8) & 0xff; - uint64_t ui64Key = 0; - - ui64Key = bytes_to_num(datain, 6); - - // variables - uint16_t rtr, i, j, len; - uint16_t davg = 0; - static uint16_t dmin, dmax; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0, nt1, nt2, nttmp, nttest, ks1; - uint8_t par[1] = {0x00}; - uint32_t target_nt[2] = {0x00}, target_ks[2] = {0x00}; - - uint8_t par_array[4] = {0x00}; - uint16_t ncount = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - - uint32_t auth1_time, auth2_time; - static uint16_t delta_time = 0; - - LED_A_ON(); - LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); - - 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 - LED_B_ON(); - WDT_HIT(); - - davg = dmax = 0; - dmin = 2000; - delta_time = 0; - - for (rtr = 0; rtr < 17; rtr++) { - - // Test if the action was cancelled - if(BUTTON_PRESS()) { - isOK = -2; - break; - } - - // prepare next select. No need to power down the card. - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 2) Dbprintf("Nested: Halt error"); - rtr--; - continue; - } - - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 2) 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)) { - if (MF_DBGLEVEL >= 2) Dbprintf("Nested: Auth1 error"); - rtr--; - continue; - }; - auth2_time = (delta_time) ? auth1_time + delta_time : 0; - - if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { - if (MF_DBGLEVEL >= 2) 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 - for (i = 101; i < 1200; i++) { - nttmp = prng_successor(nttmp, 1); - if (nttmp == nt2) break; - } - - if (i != 1200) { - if (rtr != 0) { - davg += i; - dmin = MIN(dmin, i); - dmax = MAX(dmax, i); - } - else { - 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; - } - } - } - - 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); - - 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 - - target_nt[i] = 0; - 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 >= 2) Dbprintf("Nested: Halt error"); - continue; - } - - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 2) Dbprintf("Nested: Can't select card"); - continue; - }; - - auth1_time = 0; - if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { - if (MF_DBGLEVEL >= 2) 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); - if (len != 4) { - if (MF_DBGLEVEL >= 2) Dbprintf("Nested: Auth2 error len=%d", len); - continue; - }; - - 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[0]); - - // Parity validity check - for (j = 0; j < 4; j++) { - par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); - } - - ncount = 0; - nttest = prng_successor(nt1, dmin - 1); - for (j = dmin; j < dmax + 1; j++) { - nttest = prng_successor(nttest, 1); - ks1 = nt2 ^ nttest; - - 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; - } - target_nt[i] = nttest; - target_ks[i] = ks1; - ncount++; - if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces - target_nt[i] = 0; - if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j); - break; - } - if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j); - } - } - if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1); - } - } - - LED_C_OFF(); - - crypto1_destroy(pcs); - - uint8_t buf[4 + 4 * 4] = {0}; - 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); - - LED_B_ON(); - cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); - LED_B_OFF(); - - if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} - -//----------------------------------------------------------------------------- -// MIFARE check keys. key count up to 85. -// -//----------------------------------------------------------------------------- -typedef struct sector_t { - uint8_t keyA[6]; - uint8_t keyB[6]; -} sector_t; - -typedef struct chk_t { - uint64_t key; - uint32_t cuid; - uint8_t cl; - uint8_t block; - uint8_t keyType; - uint8_t *uid; - struct Crypto1State *pcs; -} chk_t; - -// checks one key. -// fast select, tries 5 times to select -// -// return: -// 2 = failed to select. -// 1 = wrong key -// 0 = correct key -uint8_t chkKey( struct chk_t *c ) { - uint8_t i = 0, res = 2; - while( i < 5 ) { - // this part is from Piwi's faster nonce collecting part in Hardnested. - // assume: fast select - if (!iso14443a_fast_select_card(c->uid, c->cl)) { - ++i; - continue; - } - res = mifare_classic_authex(c->pcs, c->cuid, c->block, c->keyType, c->key, AUTH_FIRST, NULL, NULL); - - CHK_TIMEOUT(); - - // if successfull auth, send HALT - // if ( !res ) - // mifare_classic_halt_ex(c->pcs); - break; - } - return res; -} - -uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) { - - if (!iso14443a_fast_select_card(c->uid, c->cl)) - return 2; - - if ( mifare_classic_authex(c->pcs, c->cuid, c->block, 0, c->key, AUTH_FIRST, NULL, NULL) ) - return 1; - - uint8_t data[16] = {0x00}; - uint8_t res = mifare_classic_readblock(c->pcs, c->cuid, c->block, data); - - // successful read - if ( !res ) { - // data was something else than zeros. - if ( memcmp(data+10, "\x00\x00\x00\x00\x00\x00", 6) != 0) { - memcpy(keyb, data+10, 6); - res = 0; - } else { - res = 3; - } - mifare_classic_halt_ex(c->pcs); - } - return res; -} - -void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { - uint8_t status; - for (uint8_t s = 0; s < *sectorcnt; s++) { - - // skip already found A keys - if ( found[(s*2)] ) - continue; - - c->block = FirstBlockOfSector( s ); - status = chkKey( c ); - if ( status == 0 ) { - num_to_bytes(c->key, 6, k_sector[s].keyA); - found[(s*2)] = 1; - ++*foundkeys; - - if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Scan A found (%d)", c->block); - } - } -} - -void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { - uint8_t status; - for (uint8_t s = 0; s < *sectorcnt; s++) { - - // skip already found B keys - if ( found[(s*2)+1] ) - continue; - - c->block = FirstBlockOfSector( s ); - status = chkKey( c ); - if ( status == 0 ) { - num_to_bytes(c->key, 6, k_sector[s].keyB); - found[(s*2)+1] = 1; - ++*foundkeys; - - if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Scan B found (%d)", c->block); - } - } -} - -// loop all A keys, -// when A is found but not B, try to read B. -void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { - - // read Block B, if A is found. - for (uint8_t s = 0; s < *sectorcnt; ++s) { - c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1); - // A but not B - if ( found[(s*2)] && !found[(s*2)+1] ){ - c->key = bytes_to_num(k_sector[s].keyA, 6); - uint8_t status = chkKey_readb(c, k_sector[s].keyB); - if ( status == 0 ){ - found[(s*2)+1] = 1; - ++*foundkeys; - - if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Reading B found (%d)", c->block); - - // try quick find all B? - // assume: keys comes in groups. Find one B, test against all B. - c->key = bytes_to_num( k_sector[s].keyB, 6); - c->keyType = 1; - chkKey_scanB(c, k_sector, found, sectorcnt, foundkeys); - } - } - } -} -// get Chunks of keys, to test authentication against card. -// arg0 = antal sectorer -// arg0 = first time -// arg1 = clear trace -// arg2 = antal nycklar i keychunk -// datain = keys as array -void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - - // first call or - uint8_t sectorcnt = arg0 & 0xFF; // 16; - uint8_t firstchunk = (arg0 >> 8) & 0xF; - uint8_t lastchunk = (arg0 >> 12) & 0xF; - uint8_t strategy = arg1 & 0xFF; - uint8_t keyCount = arg2 & 0xFF; - uint8_t status = 0; - - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - struct chk_t chk_data; - - uint8_t allkeys = sectorcnt << 1; - - static uint32_t cuid = 0; - static uint8_t cascade_levels = 0; - static uint8_t foundkeys = 0; - static sector_t k_sector[80]; - static uint8_t found[80]; - static uint8_t *uid; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if (uid == NULL || firstchunk) { - uid = BigBuf_malloc(10); - if (uid == NULL ) { - if (MF_DBGLEVEL >= 3) Dbprintf("ChkKeys: uid malloc failed"); - goto OUT; - } - } - - LEDsoff(); - LED_A_ON(); - - if ( firstchunk ) { - - clear_trace(); - set_tracing(false); - - memset(k_sector, 0x00, 480+10); - memset(found, 0x00, sizeof(found)); - foundkeys = 0; - - iso14a_card_select_t card_info; - if ( !iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)"); - goto OUT; - } - switch (card_info.uidlen) { - case 4 : cascade_levels = 1; break; - case 7 : cascade_levels = 2; break; - case 10: cascade_levels = 3; break; - default: break; - } - - CHK_TIMEOUT(); - } - - // set check struct. - chk_data.uid = uid; - chk_data.cuid = cuid; - chk_data.cl = cascade_levels; - chk_data.pcs = pcs; - chk_data.block = 0; - - // keychunk loop - depth first one sector. - if ( strategy == 1 ) { - - uint8_t newfound = foundkeys; - - // Sector main loop - // keep track of how many sectors on card. - for (uint8_t s = 0; s < sectorcnt; ++s) { - - if ( found[(s*2)] && found[(s*2)+1] ) - continue; - - for (uint8_t i = 0; i < keyCount; ++i) { - - // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && !usb_poll_validate_length()) { - goto OUT; - } - - // found all keys? - if ( foundkeys == allkeys ) - goto OUT; - - WDT_HIT(); - - // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector - chk_data.block = FirstBlockOfSector( s ); - - // new key - chk_data.key = bytes_to_num(datain + i * 6, 6); - - // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector - - // skip already found A keys - if( !found[(s*2)] ) { - chk_data.keyType = 0; - status = chkKey( &chk_data); - if ( status == 0 ) { - memcpy(k_sector[s].keyA, datain + i * 6, 6); - found[(s*2)] = 1; - ++foundkeys; - - chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys); - - // read Block B, if A is found. - chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys); - - chk_data.block = FirstBlockOfSector( s ); - } - } - - // skip already found B keys - if( !found[(s*2)+1] ) { - chk_data.keyType = 1; - status = chkKey( &chk_data); - if ( status == 0 ) { - memcpy(k_sector[s].keyB, datain + i * 6, 6); - found[(s*2)+1] = 1; - ++foundkeys; - - chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); - } - } - - } // end keys test loop - depth first - - // assume1. if no keys found in first sector, get next keychunk from client - if ( newfound-foundkeys == 0 ) - goto OUT; - - } // end loop - sector - } // end strategy 1 - - if ( strategy == 2 ) { - // Keychunk loop - for (uint8_t i = 0; i < keyCount; i++) { - - // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && !usb_poll_validate_length()) break; - - WDT_HIT(); - - // new key - chk_data.key = bytes_to_num(datain + i * 6, 6); - - // Sector main loop - // keep track of how many sectors on card. - for (uint8_t s = 0; s < sectorcnt; ++s) { - - // found all keys? - if ( foundkeys == allkeys ) - goto OUT; - - // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector - chk_data.block = FirstBlockOfSector( s ); - - // skip already found A keys - if( !found[(s*2)] ) { - chk_data.keyType = 0; - status = chkKey( &chk_data); - if ( status == 0 ) { - memcpy(k_sector[s].keyA, datain + i * 6, 6); - found[(s*2)] = 1; - ++foundkeys; - - chkKey_scanA( &chk_data, k_sector, found, §orcnt, &foundkeys); - - // read Block B, if A is found. - chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys); - - chk_data.block = FirstBlockOfSector( s ); - } - } - - // skip already found B keys - if( !found[(s*2)+1] ) { - chk_data.keyType = 1; - status = chkKey( &chk_data); - if ( status == 0 ) { - memcpy(k_sector[s].keyB, datain + i * 6, 6); - found[(s*2)+1] = 1; - ++foundkeys; - - chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); - } - } - - - } // end loop sectors - } // end loop keys - } // end loop strategy 2 -OUT: - LEDsoff(); - - crypto1_destroy(pcs); - - // All keys found, send to client, or last keychunk from client - if (foundkeys == allkeys || lastchunk ) { - - uint64_t foo = 0; - uint16_t bar = 0; - for (uint8_t m = 0; m < 64; ++m) - foo |= (found[m] << m); - for (uint8_t m=64; m < sizeof(found); ++m) - bar |= (found[m] << (m-64)); - - uint8_t *tmp = BigBuf_malloc(480+10); - memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t) ); - num_to_bytes(foo, 8, tmp+480); - tmp[488] = bar & 0xFF; - tmp[489] = bar >> 8 & 0xFF; - cmd_send(CMD_ACK, foundkeys, 0, 0, tmp, 480+10); - - set_tracing(false); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - BigBuf_free(); BigBuf_Clear_ext(false); - } else { - // partial/none keys found - cmd_send(CMD_ACK, foundkeys, 0, 0, 0, 0); - } -} - -void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - uint8_t uid[10] = {0x00}; - - uint64_t key = 0; - uint32_t cuid = 0; - int i, res; - uint8_t blockNo = arg0 & 0xFF; - uint8_t keyType = (arg0 >> 8) & 0xFF; - uint8_t keyCount = arg2; - uint8_t cascade_levels = 0; - uint8_t isOK = 0; - bool have_uid = false; - bool clearTrace = arg1 & 0xFF; - - LEDsoff(); - LED_A_ON(); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if (clearTrace) - clear_trace(); - - set_tracing(true); - - for (i = 0; i < keyCount; i++) { - - // Iceman: use piwi's faster nonce collecting part in hardnested. - 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("ChkKeys: Can't select card (ALL)"); - --i; // try same key once again - 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("ChkKeys: Can't select card (UID)"); - --i; // try same key once again - continue; - } - } - - key = bytes_to_num(datain + i * 6, 6); - res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST); - - CHK_TIMEOUT(); - - if (res) - continue; - - isOK = 1; - break; - } - - LED_B_ON(); - cmd_send(CMD_ACK, isOK, 0, 0, datain + i * 6, 6); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - - set_tracing(false); - crypto1_destroy(pcs); -} - -//----------------------------------------------------------------------------- -// MIFARE commands set debug level -// -//----------------------------------------------------------------------------- -void MifareSetDbgLvl(uint16_t arg0){ - MF_DBGLEVEL = arg0; - Dbprintf("Debug level: %d", MF_DBGLEVEL); -} - -//----------------------------------------------------------------------------- -// 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); - if (arg2==0) arg2 = 16; // backwards compat... default bytewidth - emlSetMem_xt(datain, arg0, arg1, arg2); // data, block num, blocks count, block byte width -} - -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] = {0x00}; - emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4) - - LED_B_ON(); - cmd_send(CMD_ACK,arg0,arg1,0,buf,USB_CMD_DATA_SIZE); - 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; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // variables - byte_t dataoutbuf[16] = {0x00}; - byte_t dataoutbuf2[16] = {0x00}; - uint8_t uid[10] = {0x00}; - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - 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)) { - 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)) { - 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); - } - } - } - - } - - if(mifare_classic_halt(pcs, cuid)) - if (MF_DBGLEVEL >= 1) - Dbprintf("Halt error"); - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - - if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); - - set_tracing(false); -} - - -//----------------------------------------------------------------------------- -// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) -// -// PARAMS - workFlags -// bit 0 - need get UID -// bit 1 - need wupC -// bit 2 - need HALT after sequence -// bit 3 - need turn on FPGA before sequence -// bit 4 - need turn off FPGA -// bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) -// bit 6 - wipe tag. -//----------------------------------------------------------------------------- -// magic uid card generation 1 commands -uint8_t wupC1[] = { MIFARE_MAGICWUPC1 }; -uint8_t wupC2[] = { MIFARE_MAGICWUPC2 }; -uint8_t wipeC[] = { MIFARE_MAGICWIPEC }; - -void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain){ - - // params - uint8_t workFlags = arg0; - uint8_t blockNo = arg1; - - // detect 1a/1b - bool is1b = false; - - // variables - bool isOK = false; //assume we will get an error - uint8_t errormsg = 0x00; - uint8_t uid[10] = {0x00}; - uint8_t data[18] = {0x00}; - uint32_t cuid = 0; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - if (workFlags & MAGIC_INIT) { - LED_A_ON(); - LED_B_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - set_tracing(true); - } - - //loop doesn't loop just breaks out if error - while (true) { - // read UID and return to client with write - if (workFlags & MAGIC_UID) { - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); - errormsg = MAGIC_UID; - } - mifare_classic_halt_ex(NULL); - break; - } - - // wipe tag, fill it with zeros - if (workFlags & MAGIC_WIPE){ - ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("wupC1 error"); - errormsg = MAGIC_WIPE; - break; - } - - ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("wipeC error"); - errormsg = MAGIC_WIPE; - break; - } - - mifare_classic_halt_ex(NULL); - } - - // write block - if (workFlags & MAGIC_WUPC) { - ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("wupC1 error"); - errormsg = MAGIC_WUPC; - break; - } - - if ( !is1b ) { - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ALL) Dbprintf("Assuming Magic Gen 1B tag. [wupC2 failed]"); - is1b = true; - continue; - } - } - } - - if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("write block send command error"); - errormsg = 4; - break; - } - - memcpy(data, datain, 16); - AddCrc14A(data, 16); - - ReaderTransmit(data, sizeof(data), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("write block send data error"); - errormsg = 0; - break; - } - - if (workFlags & MAGIC_HALT) - mifare_classic_halt_ex(NULL); - - isOK = true; - break; - - } // end while - - if (isOK ) - cmd_send(CMD_ACK,1,0,0,uid,sizeof(uid)); - else - OnErrorMagic(errormsg); - - if (workFlags & MAGIC_OFF) - OnSuccessMagic(); -} - -void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain){ - - uint8_t workFlags = arg0; - uint8_t blockNo = arg1; - uint8_t errormsg = 0x00; - bool isOK = false; //assume we will get an error - - // detect 1a/1b - bool is1b = false; - - // variables - uint8_t data[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - memset(data, 0x00, sizeof(data)); - - if (workFlags & MAGIC_INIT) { - LED_A_ON(); - LED_B_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - set_tracing(true); - } - - //loop doesn't loop just breaks out if error or done - while (true) { - if (workFlags & MAGIC_WUPC) { - ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("wupC1 error"); - errormsg = MAGIC_WUPC; - break; - } - - if ( !is1b ) { - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= MF_DBG_ALL) Dbprintf("Assuming Magic Gen 1B tag. [wupC2 failed]"); - is1b = true; - continue; - } - } - } - - // read block - if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("read block send command error"); - errormsg = 0; - break; - } - - memcpy(data, receivedAnswer, sizeof(data)); - - // send HALT - if (workFlags & MAGIC_HALT) - mifare_classic_halt_ex(NULL); - - isOK = true; - break; - } - // if MAGIC_DATAIN, the data stays on device side. - if (workFlags & MAGIC_DATAIN) { - if (isOK) - memcpy(datain, data, sizeof(data)); - } else { - if (isOK) - cmd_send(CMD_ACK,1,0,0,data,sizeof(data)); - else - OnErrorMagic(errormsg); - } - - if (workFlags & MAGIC_OFF) - OnSuccessMagic(); -} - -void MifareCIdent(){ - #define GEN_1A 1 - #define GEN_1B 2 - #define GEN_2 4 - // variables - uint8_t isGen = 0; - uint8_t rec[1] = {0x00}; - uint8_t recpar[1] = {0x00}; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // Generation 1 test - ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); - if(!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) { - goto TEST2; - }; - isGen = GEN_1B; - - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) { - goto OUT; - }; - isGen = GEN_1A; - goto OUT; - -TEST2:; -/* - // Generation 2 test - - // halt previous. - mifare_classic_halt(NULL, 0); - - //select - if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - goto OUT; - }; - - // MIFARE_CLASSIC_WRITEBLOCK 0xA0 - // ACK 0x0a - uint16_t len = mifare_sendcmd_short(null, 1, 0xA0, 0, rec, recpar, NULL); - if ((len != 1) || (rec[0] != 0x0A)) { - isGen = GEN_2; - }; - */ -OUT:; - // removed the if, since some magic tags misbehavies and send an answer to it. - mifare_classic_halt_ex(NULL); - cmd_send(CMD_ACK, isGen, 0, 0, 0, 0); - // turns off - OnSuccessMagic(); -} - -void OnSuccessMagic(){ - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} -void OnErrorMagic(uint8_t reason){ - // ACK, ISOK, reason,0,0,0 - cmd_send(CMD_ACK,0,reason,0,0,0); - OnSuccessMagic(); -} - -void MifareSetMod(uint8_t mod, uint8_t *key) { - uint64_t ui64Key = bytes_to_num(key, 6); - - // variables - uint8_t isOK = 0; - uint8_t uid[10] = {0}; - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs = &mpcs; - int respLen = 0; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0}; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - 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"); - break; - } - - if(mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); - break; - } - - if (((respLen = mifare_sendcmd_short(pcs, 1, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); - break; - } - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - } - - isOK = 1; - break; - } - - crypto1_destroy(pcs); - - LED_B_ON(); - cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); - LED_B_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -// -// DESFIRE -// -void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ - byte_t dataout[12] = {0x00}; - uint8_t uid[10] = {0x00}; - uint32_t cuid = 0; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - set_tracing(true); - - int len = iso14443a_select_card(uid, NULL, &cuid, true, 0, false); - 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 dataout[12] = {0x00}; - byte_t isOK = 0; - - 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; - } - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED"); - - cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout)); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - set_tracing(false); -} \ No newline at end of file +//----------------------------------------------------------------------------- +// Merlok - June 2011, 2012 +// Gerhard de Koning Gans - May 2008 +// Hagen Fritsch - June 2010 +// Midnitesnake - Dec 2013 +// Andy Davies - Apr 2014 +// Iceman - May 2014,2015,2016 +// +// 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 A. +//----------------------------------------------------------------------------- + +#include "mifarecmd.h" +#include + +#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT +# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) +#endif +#ifndef HARDNESTED_PRE_AUTHENTICATION_LEADTIME +# define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication +#endif + +// send an incomplete dummy response in order to trigger the card's authentication failure timeout +#ifndef CHK_TIMEOUT +# define CHK_TIMEOUT() { \ + ReaderTransmit(&dummy_answer, 1, NULL); \ + uint32_t timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT; \ + while (GetCountSspClk() < timeout) {}; \ + } +#endif + +static uint8_t dummy_answer = 0; + +//----------------------------------------------------------------------------- +// Select, Authenticate, Read a MIFARE tag. +// read block +//----------------------------------------------------------------------------- +void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain) { + // params + uint64_t ui64Key = 0; + ui64Key = bytes_to_num(datain, 6); + + // variables + uint8_t dataoutbuf[16] = {0x00}; + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0, status = PM3_EOPABORTED; + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if (mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { + if (DBGLEVEL >= 1) Dbprintf("Read block error"); + break; + }; + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + status = PM3_SUCCESS; + break; + } + + crypto1_destroy(pcs); + + if (DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + + LED_B_ON(); + reply_ng(CMD_MIFARE_READBL, status, dataoutbuf, 16); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes) { + + bool turnOffField = (arg0 == 1); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + OnError(0); + return; + }; + + if (!mifare_ultra_auth(keybytes)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Authentication failed"); + OnError(1); + return; + } + + if (turnOffField) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + } + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); +} + +// Arg0 = BlockNo, +// Arg1 = UsePwd bool +// datain = PWD bytes, +void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + uint8_t blockNo = arg0; + uint8_t dataout[16] = {0x00}; + bool useKey = (arg1 == 1); //UL_C + bool usePwd = (arg1 == 2); //UL_EV1/NTAG + + LEDsoff(); + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); + if (!len) { + if (DBGLEVEL >= 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 (DBGLEVEL >= DBG_ERROR) Dbprintf("Read block error"); + OnError(2); + return; + } + + if (mifare_ultra_halt()) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); + OnError(3); + return; + } + + reply_mix(CMD_ACK, 1, 0, 0, dataout, 16); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +//----------------------------------------------------------------------------- +// Select, Authenticate, Read a MIFARE tag. +// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) +//----------------------------------------------------------------------------- +void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + // params + uint8_t sectorNo = arg0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + ui64Key = bytes_to_num(datain, 6); + + // variables + uint8_t isOK = 0; + uint8_t dataoutbuf[16 * 16]; + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + isOK = 1; + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + isOK = 0; + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + } + + + if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { + isOK = 0; + if (DBGLEVEL >= 1) Dbprintf("Auth error"); + } + + for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { + if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { + isOK = 0; + if (DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); + break; + } + } + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + } + + if (DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); + + crypto1_destroy(pcs); + + LED_B_ON(); + reply_old(CMD_ACK, isOK, 0, 0, dataoutbuf, 16 * NumBlocksPerSector(sectorNo)); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + +// 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) { + LEDsoff(); + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // free eventually allocated BigBuf memory + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + // 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 (DBGLEVEL >= 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 (DBGLEVEL >= 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 (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); + OnError(3); + return; + } + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks); + + countblocks *= 4; + + reply_mix(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + BigBuf_free(); + set_tracing(false); +} + +//----------------------------------------------------------------------------- +// Select, Authenticate, Write a MIFARE tag. +// read block +//----------------------------------------------------------------------------- +void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + uint8_t blockdata[16] = {0x00}; + + ui64Key = bytes_to_num(datain, 6); + memcpy(blockdata, datain + 10, 16); + + // variables + uint8_t isOK = 0; + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { + if (DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + crypto1_destroy(pcs); + + if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + reply_mix(CMD_ACK, isOK, 0, 0, 0, 0); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + +/* // Command not needed but left for future testing +void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) +{ + uint8_t blockNo = arg0; + uint8_t blockdata[16] = {0x00}; + + memcpy(blockdata, datain, 16); + + uint8_t uid[10] = {0x00}; + + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); + + clear_trace(); + set_tracing(true); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + OnError(0); + return; + }; + + if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { + if (DBGLEVEL >= 1) Dbprintf("Write block error"); + OnError(0); + return; }; + + if(mifare_ultra_halt()) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + OnError(0); + return; + }; + + if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + reply_mix(CMD_ACK,1,0,0,0,0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + 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 + uint8_t blockdata[4] = {0x00}; + + memcpy(blockdata, datain, 4); + + LEDsoff(); + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (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 (DBGLEVEL >= 1) Dbprintf("Write block error"); + OnError(0); + return; + }; + + if (mifare_ultra_halt()) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + OnError(0); + return; + }; + + if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + +void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { + + uint8_t pwd[16] = {0x00}; + uint8_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(); + set_tracing(true); + + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (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 (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 (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 (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 (DBGLEVEL >= 1) Dbprintf("Write block error"); + OnError(47); + return; + }; + + if (mifare_ultra_halt()) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + OnError(0); + return; + }; + + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + +// 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; +} + +void MifareAcquireNonces(uint32_t arg0, uint32_t flags) { + + uint8_t uid[10] = {0x00}; + uint8_t answer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t par[1] = {0x00}; + uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; + uint32_t cuid = 0; + int16_t isOK = 0; + uint16_t num_nonces = 0; + uint8_t cascade_levels = 0; + uint8_t blockNo = arg0 & 0xff; + uint8_t keyType = (arg0 >> 8) & 0xff; + bool initialize = flags & 0x0001; + bool field_off = flags & 0x0004; + bool have_uid = false; + + LED_A_ON(); + LED_C_OFF(); + + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + if (initialize) + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_C_ON(); + + for (uint16_t i = 0; i <= PM3_CMD_DATA_SIZE - 4; i += 4) { + + // 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 (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_fast_select_card(uid, cascade_levels)) { + if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + continue; + } + } + + // Transmit MIFARE_CLASSIC_AUTH + uint8_t dcmd[4] = {0x60 + (keyType & 0x01), blockNo, 0x00, 0x00}; + AddCrc14A(dcmd, 2); + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer, par); + + // wait for the card to become ready again + CHK_TIMEOUT(); + + if (len != 4) { + if (DBGLEVEL >= 2) Dbprintf("AcquireNonces: Auth1 error"); + continue; + } + + num_nonces++; + + // Save the tag nonce (nt) + buf[i] = answer[0]; + buf[i + 1] = answer[1]; + buf[i + 2] = answer[2]; + buf[i + 3] = answer[3]; + } + + LED_C_OFF(); + LED_B_ON(); + reply_old(CMD_ACK, isOK, cuid, num_nonces - 1, buf, sizeof(buf)); + LED_B_OFF(); + + if (DBGLEVEL >= 3) DbpString("AcquireNonces finished"); + + if (field_off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); + } +} + +//----------------------------------------------------------------------------- +// 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) { + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + uint8_t uid[10] = {0x00}; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t par_enc[1] = {0x00}; + uint8_t buf[PM3_CMD_DATA_SIZE] = {0x00}; + + uint64_t ui64Key = bytes_to_num(datain, 6); + uint32_t cuid = 0; + int16_t isOK = 0; + uint16_t num_nonces = 0; + uint8_t nt_par_enc = 0; + uint8_t cascade_levels = 0; + uint8_t blockNo = arg0 & 0xff; + uint8_t keyType = (arg0 >> 8) & 0xff; + uint8_t targetBlockNo = arg1 & 0xff; + uint8_t targetKeyType = (arg1 >> 8) & 0xff; + bool initialize = flags & 0x0001; + bool slow = flags & 0x0002; + bool field_off = flags & 0x0004; + bool have_uid = false; + + LED_A_ON(); + LED_C_OFF(); + + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(false); + + if (initialize) + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_C_ON(); + + for (uint16_t i = 0; i <= PM3_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 (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_fast_select_card(uid, cascade_levels)) { + if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + continue; + } + } + + if (slow) + SpinDelayUs(HARDNESTED_PRE_AUTHENTICATION_LEADTIME); + + uint32_t nt1; + if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { + if (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); + + // wait for the card to become ready again + CHK_TIMEOUT(); + + if (len != 4) { + if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); + continue; + } + + 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; + } + } + + LED_C_OFF(); + crypto1_destroy(pcs); + LED_B_ON(); + reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); + LED_B_OFF(); + + if (DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); + + if (field_off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); + } +} + + +//----------------------------------------------------------------------------- +// MIFARE nested authentication. +// +//----------------------------------------------------------------------------- +void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + // params + uint8_t blockNo = arg0 & 0xff; + uint8_t keyType = (arg0 >> 8) & 0xff; + uint8_t targetBlockNo = arg1 & 0xff; + uint8_t targetKeyType = (arg1 >> 8) & 0xff; + // calibrate = arg2 + uint64_t ui64Key = 0; + + ui64Key = bytes_to_num(datain, 6); + + // variables + uint16_t i, j, len; + static uint16_t dmin, dmax; + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0, nt1, nt2, nttest, ks1; + uint8_t par[1] = {0x00}; + uint32_t target_nt[2] = {0x00}, target_ks[2] = {0x00}; + + uint8_t par_array[4] = {0x00}; + uint16_t ncount = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + + uint32_t auth1_time, auth2_time; + static uint16_t delta_time = 0; + + LED_A_ON(); + LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // free eventually allocated BigBuf memory + BigBuf_free(); + BigBuf_Clear_ext(false); + + if (arg2) clear_trace(); + set_tracing(true); + + // statistics on nonce distance + int16_t isOK = 0; +#define NESTED_MAX_TRIES 12 + if (arg2) { // calibrate: for first call only. Otherwise reuse previous calibration + LED_B_ON(); + WDT_HIT(); + + uint16_t unsuccessfull_tries = 0; + uint16_t davg = 0; + dmax = 0; + dmin = 2000; + delta_time = 0; + uint16_t rtr; + for (rtr = 0; rtr < 17; rtr++) { + + // Test if the action was cancelled + if (BUTTON_PRESS()) { + isOK = -2; + break; + } + + // prepare next select. No need to power down the card. + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= 2) Dbprintf("Nested: Halt error"); + rtr--; + continue; + } + + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= 2) 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)) { + if (DBGLEVEL >= 2) Dbprintf("Nested: Auth1 error"); + rtr--; + continue; + }; + auth2_time = (delta_time) ? auth1_time + delta_time : 0; + + if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { + if (DBGLEVEL >= 2) Dbprintf("Nested: Auth2 error"); + rtr--; + continue; + }; + + uint32_t 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) break; + } + + if (i != 1200) { + if (rtr != 0) { + davg += i; + dmin = MIN(dmin, i); + dmax = MAX(dmax, i); + } else { + delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing + } + if (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; + } + } + } + + davg = (davg + (rtr - 1) / 2) / (rtr - 1); + + if (DBGLEVEL >= 3) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, 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 + + target_nt[i] = 0; + 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 (DBGLEVEL >= 2) Dbprintf("Nested: Halt error"); + continue; + } + + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= 2) Dbprintf("Nested: Can't select card"); + continue; + }; + + auth1_time = 0; + if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { + if (DBGLEVEL >= 2) 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); + if (len != 4) { + if (DBGLEVEL >= 2) Dbprintf("Nested: Auth2 error len=%d", len); + continue; + }; + + nt2 = bytes_to_num(receivedAnswer, 4); + if (DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i + 1, nt1, nt2, par[0]); + + // Parity validity check + for (j = 0; j < 4; j++) { + par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7 - j)) & 0x01)); + } + + ncount = 0; + nttest = prng_successor(nt1, dmin - 1); + for (j = dmin; j < dmax + 1; j++) { + nttest = prng_successor(nttest, 1); + ks1 = nt2 ^ nttest; + + if (valid_nonce(nttest, nt2, ks1, par_array)) { + if (ncount > 0) { // we are only interested in disambiguous nonces, try again + if (DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i + 1, j); + target_nt[i] = 0; + break; + } + target_nt[i] = nttest; + target_ks[i] = ks1; + ncount++; + if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces + target_nt[i] = 0; + if (DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j); + break; + } + if (DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i + 1, j); + } + } + if (target_nt[i] == 0 && j == dmax + 1 && DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i + 1); + } + } + + LED_C_OFF(); + + crypto1_destroy(pcs); + + uint8_t buf[4 + 4 * 4] = {0}; + 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); + + LED_B_ON(); + reply_mix(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); + LED_B_OFF(); + + if (DBGLEVEL >= 3) DbpString("NESTED FINISHED"); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + +//----------------------------------------------------------------------------- +// MIFARE check keys. key count up to 85. +// +//----------------------------------------------------------------------------- +typedef struct sector_t { + uint8_t keyA[6]; + uint8_t keyB[6]; +} sector_t; + +typedef struct chk_t { + uint64_t key; + uint32_t cuid; + uint8_t cl; + uint8_t block; + uint8_t keyType; + uint8_t *uid; + struct Crypto1State *pcs; +} chk_t; + +// checks one key. +// fast select, tries 5 times to select +// +// return: +// 2 = failed to select. +// 1 = wrong key +// 0 = correct key +uint8_t chkKey(struct chk_t *c) { + uint8_t i = 0, res = 2; + while (i < 5) { + // this part is from Piwi's faster nonce collecting part in Hardnested. + // assume: fast select + if (!iso14443a_fast_select_card(c->uid, c->cl)) { + ++i; + continue; + } + res = mifare_classic_authex(c->pcs, c->cuid, c->block, c->keyType, c->key, AUTH_FIRST, NULL, NULL); + + CHK_TIMEOUT(); + + // if successfull auth, send HALT + // if ( !res ) + // mifare_classic_halt_ex(c->pcs); + break; + } + return res; +} + +uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) { + + if (!iso14443a_fast_select_card(c->uid, c->cl)) + return 2; + + if (mifare_classic_authex(c->pcs, c->cuid, c->block, 0, c->key, AUTH_FIRST, NULL, NULL)) + return 1; + + uint8_t data[16] = {0x00}; + uint8_t res = mifare_classic_readblock(c->pcs, c->cuid, c->block, data); + + // successful read + if (!res) { + // data was something else than zeros. + if (memcmp(data + 10, "\x00\x00\x00\x00\x00\x00", 6) != 0) { + memcpy(keyb, data + 10, 6); + res = 0; + } else { + res = 3; + } + mifare_classic_halt_ex(c->pcs); + } + return res; +} + +void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { + for (uint8_t s = 0; s < *sectorcnt; s++) { + + // skip already found A keys + if (found[(s * 2)]) + continue; + + c->block = FirstBlockOfSector(s); + if (chkKey(c) == 0) { + num_to_bytes(c->key, 6, k_sector[s].keyA); + found[(s * 2)] = 1; + ++*foundkeys; + + if (DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Scan A found (%d)", c->block); + } + } +} + +void chkKey_scanB(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { + for (uint8_t s = 0; s < *sectorcnt; s++) { + + // skip already found B keys + if (found[(s * 2) + 1]) + continue; + + c->block = FirstBlockOfSector(s); + if (chkKey(c) == 0) { + num_to_bytes(c->key, 6, k_sector[s].keyB); + found[(s * 2) + 1] = 1; + ++*foundkeys; + + if (DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Scan B found (%d)", c->block); + } + } +} + +// loop all A keys, +// when A is found but not B, try to read B. +void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) { + + // read Block B, if A is found. + for (uint8_t s = 0; s < *sectorcnt; ++s) { + + if (found[(s * 2)] && found[(s * 2) + 1]) + continue; + + c->block = (FirstBlockOfSector(s) + NumBlocksPerSector(s) - 1); + + // A but not B + if (found[(s * 2)] && !found[(s * 2) + 1]) { + c->key = bytes_to_num(k_sector[s].keyA, 6); + uint8_t status = chkKey_readb(c, k_sector[s].keyB); + if (status == 0) { + found[(s * 2) + 1] = 1; + ++*foundkeys; + + if (DBGLEVEL >= 3) Dbprintf("ChkKeys_fast: Reading B found (%d)", c->block); + + // try quick find all B? + // assume: keys comes in groups. Find one B, test against all B. + c->key = bytes_to_num(k_sector[s].keyB, 6); + c->keyType = 1; + chkKey_scanB(c, k_sector, found, sectorcnt, foundkeys); + } + } + } +} + + + +// get Chunks of keys, to test authentication against card. +// arg0 = antal sectorer +// arg0 = first time +// arg1 = clear trace +// arg2 = antal nycklar i keychunk +// datain = keys as array +void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + + // first call or + uint8_t sectorcnt = arg0 & 0xFF; // 16; + uint8_t firstchunk = (arg0 >> 8) & 0xF; + uint8_t lastchunk = (arg0 >> 12) & 0xF; + uint8_t strategy = arg1 & 0xFF; + uint8_t use_flashmem = (arg1 >> 8) & 0xFF; + uint16_t keyCount = arg2 & 0xFF; + uint8_t status = 0; + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + struct chk_t chk_data; + + uint8_t allkeys = sectorcnt << 1; + + static uint32_t cuid = 0; + static uint8_t cascade_levels = 0; + static uint8_t foundkeys = 0; + static sector_t k_sector[80]; + static uint8_t found[80]; + static uint8_t *uid; + +#ifdef WITH_FLASH + if (use_flashmem) { + BigBuf_free(); + uint16_t isok = 0; + uint8_t size[2] = {0x00, 0x00}; + isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET, size, 2); + if (isok != 2) + goto OUT; + + keyCount = size[1] << 8 | size[0]; + + if (keyCount == 0 || keyCount == 0xFFFF) + goto OUT; + + datain = BigBuf_malloc(keyCount * 6); + if (datain == NULL) + goto OUT; + + isok = Flash_ReadData(DEFAULT_MF_KEYS_OFFSET + 2, datain, keyCount * 6); + if (isok != keyCount * 6) + goto OUT; + + } +#endif + + if (uid == NULL || firstchunk) { + uid = BigBuf_malloc(10); + if (uid == NULL) + goto OUT; + } + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LEDsoff(); + LED_A_ON(); + + if (firstchunk) { + clear_trace(); + set_tracing(false); + + memset(k_sector, 0x00, 480 + 10); + memset(found, 0x00, sizeof(found)); + foundkeys = 0; + + iso14a_card_select_t card_info; + if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)"); + goto OUT; + } + + switch (card_info.uidlen) { + case 4 : + cascade_levels = 1; + break; + case 7 : + cascade_levels = 2; + break; + case 10: + cascade_levels = 3; + break; + default: + break; + } + + CHK_TIMEOUT(); + } + + // set check struct. + chk_data.uid = uid; + chk_data.cuid = cuid; + chk_data.cl = cascade_levels; + chk_data.pcs = pcs; + chk_data.block = 0; + + // keychunk loop - depth first one sector. + if (strategy == 1 || use_flashmem) { + + uint8_t newfound = foundkeys; + + uint16_t lastpos = 0; + uint16_t s_point = 0; + // Sector main loop + // keep track of how many sectors on card. + for (uint8_t s = 0; s < sectorcnt; ++s) { + + if (found[(s * 2)] && found[(s * 2) + 1]) + continue; + + for (uint16_t i = s_point; i < keyCount; ++i) { + + //if ( i % 100 == 0) Dbprintf("ChkKeys_fast: sector %d | checking %d | %d found | s_point %d", s, i, foundkeys, s_point); + + // Allow button press / usb cmd to interrupt device + if (BUTTON_PRESS() && !data_available()) { + goto OUT; + } + + // found all keys? + if (foundkeys == allkeys) + goto OUT; + + WDT_HIT(); + + // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector + chk_data.block = FirstBlockOfSector(s); + + // new key + chk_data.key = bytes_to_num(datain + i * 6, 6); + + // skip already found A keys + if (!found[(s * 2)]) { + chk_data.keyType = 0; + status = chkKey(&chk_data); + if (status == 0) { + memcpy(k_sector[s].keyA, datain + i * 6, 6); + found[(s * 2)] = 1; + ++foundkeys; + + chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys); + + // read Block B, if A is found. + chkKey_loopBonly(&chk_data, k_sector, found, §orcnt, &foundkeys); + + chk_data.keyType = 1; + chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); + + chk_data.keyType = 0; + chk_data.block = FirstBlockOfSector(s); + + if (use_flashmem) { + if (lastpos != i && lastpos != 0) { + if (i - lastpos < 0xF) { + s_point = i & 0xFFF0; + } + } else { + lastpos = i; + } + } + } + } + + // skip already found B keys + if (!found[(s * 2) + 1]) { + chk_data.keyType = 1; + status = chkKey(&chk_data); + if (status == 0) { + memcpy(k_sector[s].keyB, datain + i * 6, 6); + found[(s * 2) + 1] = 1; + ++foundkeys; + + chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); + + if (use_flashmem) { + if (lastpos != i && lastpos != 0) { + + if (i - lastpos < 0xF) + s_point = i & 0xFFF0; + } else { + lastpos = i; + } + } + } + } + + if (found[(s * 2)] && found[(s * 2) + 1]) + break; + + } // end keys test loop - depth first + + // assume1. if no keys found in first sector, get next keychunk from client + if (!use_flashmem && (newfound - foundkeys == 0)) + goto OUT; + + } // end loop - sector + } // end strategy 1 + + if (foundkeys == allkeys) + goto OUT; + + if (strategy == 2 || use_flashmem) { + + // Keychunk loop + for (uint16_t i = 0; i < keyCount; i++) { + + // Allow button press / usb cmd to interrupt device + if (BUTTON_PRESS() && !data_available()) break; + + // found all keys? + if (foundkeys == allkeys) + goto OUT; + + WDT_HIT(); + + // new key + chk_data.key = bytes_to_num(datain + i * 6, 6); + + // Sector main loop + // keep track of how many sectors on card. + for (uint8_t s = 0; s < sectorcnt; ++s) { + + if (found[(s * 2)] && found[(s * 2) + 1]) continue; + + // found all keys? + if (foundkeys == allkeys) + goto OUT; + + // assume: block0,1,2 has more read rights in accessbits than the sectortrailer. authenticating against block0 in each sector + chk_data.block = FirstBlockOfSector(s); + + // skip already found A keys + if (!found[(s * 2)]) { + chk_data.keyType = 0; + status = chkKey(&chk_data); + if (status == 0) { + memcpy(k_sector[s].keyA, datain + i * 6, 6); + found[(s * 2)] = 1; + ++foundkeys; + + chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys); + + // read Block B, if A is found. + chkKey_loopBonly(&chk_data, k_sector, found, §orcnt, &foundkeys); + + chk_data.block = FirstBlockOfSector(s); + } + } + + // skip already found B keys + if (!found[(s * 2) + 1]) { + chk_data.keyType = 1; + status = chkKey(&chk_data); + if (status == 0) { + memcpy(k_sector[s].keyB, datain + i * 6, 6); + found[(s * 2) + 1] = 1; + ++foundkeys; + + chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys); + } + } + } // end loop sectors + } // end loop keys + } // end loop strategy 2 +OUT: + LEDsoff(); + + crypto1_destroy(pcs); + + // All keys found, send to client, or last keychunk from client + if (foundkeys == allkeys || lastchunk) { + + uint64_t foo = 0; + for (uint8_t m = 0; m < 64; m++) { + foo |= ((uint64_t)(found[m] & 1) << m); + } + + uint16_t bar = 0; + uint8_t j = 0; + for (uint8_t m = 64; m < sizeof(found); m++) { + bar |= ((uint16_t)(found[m] & 1) << j++); + } + + uint8_t *tmp = BigBuf_malloc(480 + 10); + memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t)); + num_to_bytes(foo, 8, tmp + 480); + tmp[488] = bar & 0xFF; + tmp[489] = bar >> 8 & 0xFF; + + reply_old(CMD_ACK, foundkeys, 0, 0, tmp, 480 + 10); + + set_tracing(false); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + BigBuf_free(); + BigBuf_Clear_ext(false); + } else { + // partial/none keys found + reply_mix(CMD_ACK, foundkeys, 0, 0, 0, 0); + } +} + +void MifareChkKeys(uint8_t *datain) { + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + uint8_t uid[10] = {0x00}; + + uint64_t key = 0; + uint32_t cuid = 0; + int i, res; + uint8_t cascade_levels = 0; + struct { + uint8_t key[6]; + bool found; + } PACKED keyresult; + keyresult.found = false; + uint8_t blockNo, keyType, keyCount; + bool clearTrace, have_uid = false; + + keyType = datain[0]; + blockNo = datain[1]; + clearTrace = datain[2]; + keyCount = datain[3]; + datain += 4; + + LEDsoff(); + LED_A_ON(); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + if (clearTrace) + clear_trace(); + + set_tracing(true); + + for (i = 0; i < keyCount; i++) { + + // Iceman: use piwi's faster nonce collecting part in hardnested. + if (!have_uid) { // need a full select cycle to get the uid first + iso14a_card_select_t card_info; + if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)"); + --i; // try same key once again + 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 (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)"); + --i; // try same key once again + continue; + } + } + + key = bytes_to_num(datain + i * 6, 6); + res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST); + + CHK_TIMEOUT(); + + if (res) + continue; + memcpy(keyresult.key, datain + i * 6, 6); + keyresult.found = true; + break; + } + + LED_B_ON(); + + reply_ng(CMD_MIFARE_CHKKEYS, PM3_SUCCESS, (uint8_t *)&keyresult, sizeof(keyresult)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + set_tracing(false); + crypto1_destroy(pcs); +} + +//----------------------------------------------------------------------------- +// 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(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + emlClearMem(); +} + +void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + if (blockwidth == 0) + blockwidth = 16; // backwards compat... default bytewidth + + emlSetMem_xt(datain, blockno, blockcnt, blockwidth); // data, block num, blocks count, block byte width +} + +void MifareEMemGet(uint8_t blockno, uint8_t blockcnt) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // + size_t size = blockcnt * 16; + if (size > PM3_CMD_DATA_SIZE) { + reply_ng(CMD_MIFARE_EML_MEMGET, PM3_EMALLOC, NULL, 0); + return; + } + + uint8_t *buf = BigBuf_malloc(size); + + emlGetMem(buf, blockno, blockcnt); // data, block num, blocks count (max 4) + + LED_B_ON(); + reply_ng(CMD_MIFARE_EML_MEMGET, PM3_SUCCESS, buf, size); + LED_B_OFF(); + BigBuf_free_keep_EM(); +} + +//----------------------------------------------------------------------------- +// Load a card into the emulator memory +// +//----------------------------------------------------------------------------- +int MifareECardLoad(uint32_t arg0, uint32_t arg1) { + uint32_t cuid = 0; + uint8_t numSectors = arg0; + uint8_t keyType = arg1; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // variables + uint8_t dataoutbuf[16] = {0x00}; + uint8_t dataoutbuf2[16] = {0x00}; + uint8_t uid[10] = {0x00}; + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + bool isOK = true; + + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + isOK = false; + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + } + + for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { + uint64_t ui64Key = emlGetKey(sectorNo, keyType); + if (sectorNo == 0) { + if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { + if (DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); + break; + } + } else { + if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { + isOK = false; + if (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 (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); + } + } + } + + } + + if (mifare_classic_halt(pcs, cuid)) + if (DBGLEVEL >= 1) + Dbprintf("Halt error"); + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + if (DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); + + set_tracing(false); + return (isOK) ? PM3_SUCCESS : PM3_EUNDEF; +} + + +//----------------------------------------------------------------------------- +// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) +// +// PARAMS - workFlags +// bit 0 - need get UID +// bit 1 - need wupC +// bit 2 - need HALT after sequence +// bit 3 - need turn on FPGA before sequence +// bit 4 - need turn off FPGA +// bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) +// bit 6 - wipe tag. +//----------------------------------------------------------------------------- +// magic uid card generation 1 commands +uint8_t wupC1[] = { MIFARE_MAGICWUPC1 }; +uint8_t wupC2[] = { MIFARE_MAGICWUPC2 }; +uint8_t wipeC[] = { MIFARE_MAGICWIPEC }; + +void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { + + // params + uint8_t workFlags = arg0; + uint8_t blockNo = arg1; + + // detect 1a/1b + bool is1b = false; + + // variables + bool isOK = false; //assume we will get an error + uint8_t errormsg = 0x00; + uint8_t uid[10] = {0x00}; + uint8_t data[18] = {0x00}; + uint32_t cuid = 0; + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + if (workFlags & MAGIC_INIT) { + LED_A_ON(); + LED_B_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + } + + //loop doesn't loop just breaks out if error + while (true) { + // read UID and return to client with write + if (workFlags & MAGIC_UID) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + errormsg = MAGIC_UID; + } + mifare_classic_halt_ex(NULL); + break; + } + + // wipe tag, fill it with zeros + if (workFlags & MAGIC_WIPE) { + ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("wupC1 error"); + errormsg = MAGIC_WIPE; + break; + } + + ReaderTransmit(wipeC, sizeof(wipeC), NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("wipeC error"); + errormsg = MAGIC_WIPE; + break; + } + + mifare_classic_halt_ex(NULL); + } + + // write block + if (workFlags & MAGIC_WUPC) { + ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("wupC1 error"); + errormsg = MAGIC_WUPC; + break; + } + + if (!is1b) { + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Assuming Magic Gen 1B tag. [wupC2 failed]"); + is1b = true; + continue; + } + } + } + + if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("write block send command error"); + errormsg = 4; + break; + } + + memcpy(data, datain, 16); + AddCrc14A(data, 16); + + ReaderTransmit(data, sizeof(data), NULL); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("write block send data error"); + errormsg = 0; + break; + } + + if (workFlags & MAGIC_HALT) + mifare_classic_halt_ex(NULL); + + isOK = true; + break; + + } // end while + + if (isOK) + reply_mix(CMD_ACK, 1, 0, 0, uid, sizeof(uid)); + else + OnErrorMagic(errormsg); + + if (workFlags & MAGIC_OFF) + OnSuccessMagic(); +} + +void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { + + uint8_t workFlags = arg0; + uint8_t blockNo = arg1; + uint8_t errormsg = 0x00; + bool isOK = false; //assume we will get an error + + // detect 1a/1b + bool is1b = false; + + // variables + uint8_t data[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + memset(data, 0x00, sizeof(data)); + + if (workFlags & MAGIC_INIT) { + LED_A_ON(); + LED_B_OFF(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + } + + //loop doesn't loop just breaks out if error or done + while (true) { + if (workFlags & MAGIC_WUPC) { + ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("wupC1 error"); + errormsg = MAGIC_WUPC; + break; + } + + if (!is1b) { + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Assuming Magic Gen 1B tag. [wupC2 failed]"); + is1b = true; + continue; + } + } + } + + // read block + if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("read block send command error"); + errormsg = 0; + break; + } + + memcpy(data, receivedAnswer, sizeof(data)); + + // send HALT + if (workFlags & MAGIC_HALT) + mifare_classic_halt_ex(NULL); + + isOK = true; + break; + } + // if MAGIC_DATAIN, the data stays on device side. + if (workFlags & MAGIC_DATAIN) { + if (isOK) + memcpy(datain, data, sizeof(data)); + } else { + if (isOK) + reply_old(CMD_ACK, 1, 0, 0, data, sizeof(data)); + else + OnErrorMagic(errormsg); + } + + if (workFlags & MAGIC_OFF) + OnSuccessMagic(); +} + +void MifareCIdent() { +#define GEN_1A 1 +#define GEN_1B 2 +#define GEN_2 4 + // variables + uint8_t isGen = 0; + uint8_t rec[1] = {0x00}; + uint8_t recpar[1] = {0x00}; + uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 }; + uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); + uint8_t *uid = BigBuf_malloc(10); + uint32_t cuid = 0; + uint8_t data[1] = {0x00}; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // Generation 1 test + ReaderTransmitBitsPar(wupC1, 7, NULL, NULL); + if (!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) { + goto TEST2; + }; + + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if (!ReaderReceive(rec, recpar) || (rec[0] != 0x0a)) { + isGen = GEN_1B; + goto OUT; + }; + isGen = GEN_1A; + goto OUT; + +TEST2: + // reset card + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); + if (res == 2) { + ReaderTransmit(rats, sizeof(rats), NULL); + res = ReaderReceive(buf, par); + if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) { + isGen = GEN_2; + goto OUT; + } + if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) { + isGen = GEN_2; + } + }; + +OUT: + + data[0] = isGen; + reply_ng(CMD_MIFARE_CIDENT, PM3_SUCCESS, data, sizeof(data)); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + +void OnSuccessMagic() { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} +void OnErrorMagic(uint8_t reason) { + // ACK, ISOK, reason,0,0,0 + reply_mix(CMD_ACK, 0, reason, 0, 0, 0); + OnSuccessMagic(); +} + +void MifareSetMod(uint8_t *datain) { + + uint8_t mod = datain[0]; + uint64_t ui64Key = bytes_to_num(datain + 1, 6); + + // variables + uint16_t isOK = PM3_EUNDEF; + uint8_t uid[10] = {0}; + uint32_t cuid = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs = &mpcs; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0}; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + } + + if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) { + if (DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + } + + int respLen; + if (((respLen = mifare_sendcmd_short(pcs, 1, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { + if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); + break; + } + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + } + + isOK = PM3_SUCCESS; + break; + } + + crypto1_destroy(pcs); + + LED_B_ON(); + reply_ng(CMD_MIFARE_SETMOD, isOK, NULL, 0); + + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +// +// DESFIRE +// +void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain) { + uint8_t dataout[12] = {0x00}; + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + int len = iso14443a_select_card(uid, NULL, &cuid, true, 0, false); + if (!len) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + OnError(1); + return; + }; + + if (mifare_desfire_des_auth1(cuid, dataout)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Authentication part1: Fail."); + OnError(4); + return; + } + + if (DBGLEVEL >= DBG_EXTENDED) DbpString("AUTH 1 FINISHED"); + reply_mix(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}; + uint8_t dataout[12] = {0x00}; + uint8_t isOK = 0; + + memcpy(key, datain, 16); + + isOK = mifare_desfire_des_auth2(cuid, key, dataout); + + if (isOK) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); + OnError(4); + return; + } + + if (DBGLEVEL >= DBG_EXTENDED) DbpString("AUTH 2 FINISHED"); + + reply_old(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index d73b124cb..5e4a5cf97 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -1,28 +1,27 @@ -//----------------------------------------------------------------------------- -// 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 A. -//----------------------------------------------------------------------------- - -#ifndef __MIFARECMD_H -#define __MIFARECMD_H - -#include "proxmark3.h" -#include "apps.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" -#include "crc.h" -#include "protocols.h" -#include "parity.h" -#endif \ No newline at end of file +//----------------------------------------------------------------------------- +// 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 A. +//----------------------------------------------------------------------------- + +#ifndef __MIFARECMD_H +#define __MIFARECMD_H + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" +#include "iso14443a.h" +#include "crapto1/crapto1.h" +#include "mifareutil.h" +#include "common.h" +#include "crc.h" +#include "protocols.h" +#include "parity.h" +#endif diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index 81a29578b..bda31790d 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -10,304 +10,303 @@ // the block number for the ISO14443-4 PCB 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 uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4}; //static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 }; /* PCB CID CMD PAYLOAD */ //static uint8_t __res[MAX_FRAME_SIZE]; -bool InitDesfireCard(){ +bool InitDesfireCard() { - iso14a_card_select_t card; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - set_tracing(true); + iso14a_card_select_t card; - if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) DbpString("Can't select card"); - OnError(1); - return false; - } - return true; + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + set_tracing(true); + + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { + if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card"); + OnError(1); + return false; + } + return true; } // ARG0 flag enums enum { - NONE = 0x00, - INIT = 0x01, - DISCONNECT = 0x02, - CLEARTRACE = 0x04, - BAR = 0x08, + NONE = 0x00, + INIT = 0x01, + DISCONNECT = 0x02, + CLEARTRACE = 0x04, + BAR = 0x08, } CmdOptions ; -void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){ - - /* ARG0 contains flags. - 0x01 = init card. - 0x02 = Disconnect - 0x03 - */ - uint8_t flags = arg0; - size_t datalen = arg1; - uint8_t resp[RECEIVE_SIZE]; - memset(resp,0,sizeof(resp)); - - if (MF_DBGLEVEL >= 4) { - Dbprintf(" flags : %02X", flags); - Dbprintf(" len : %02X", datalen); - print_result(" RX : ", datain, datalen); - } - - if ( flags & CLEARTRACE ) - clear_trace(); - - if ( flags & INIT ){ - if ( !InitDesfireCard() ) - return; - } - - int len = DesfireAPDU(datain, datalen, resp); - if (MF_DBGLEVEL >= 4) - print_result("ERR <--: ", resp, len); +void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { - if ( !len ) { - OnError(2); - return; - } - - // reset the pcb_blocknum, - pcb_blocknum = 0; - - if ( flags & DISCONNECT ) - OnSuccess(); - - cmd_send(CMD_ACK,1,len,0,resp,len); + /* ARG0 contains flags. + 0x01 = init card. + 0x02 = Disconnect + 0x03 + */ + uint8_t flags = arg0; + size_t datalen = arg1; + uint8_t resp[RECEIVE_SIZE]; + memset(resp, 0, sizeof(resp)); + + if (DBGLEVEL >= 4) { + Dbprintf(" flags : %02X", flags); + Dbprintf(" len : %02X", datalen); + print_result(" RX : ", datain, datalen); + } + + if (flags & CLEARTRACE) + clear_trace(); + + if (flags & INIT) { + if (!InitDesfireCard()) + return; + } + + int len = DesfireAPDU(datain, datalen, resp); + if (DBGLEVEL >= 4) + print_result("ERR <--: ", resp, len); + + if (!len) { + OnError(2); + return; + } + + // reset the pcb_blocknum, + pcb_blocknum = 0; + + if (flags & DISCONNECT) + OnSuccess(); + + reply_old(CMD_ACK, 1, len, 0, resp, len); } -void MifareDesfireGetInformation(){ - - int len = 0; - iso14a_card_select_t card; - uint8_t resp[USB_CMD_DATA_SIZE] = {0x00}; - uint8_t dataout[USB_CMD_DATA_SIZE] = {0x00}; - - /* - 1 = PCB 1 - 2 = cid 2 - 3 = desfire command 3 - 4-5 = crc 4 key - 5-6 crc - PCB == 0x0A because sending CID byte. - CID == 0x00 first card? - */ - clear_trace(); - set_tracing(true); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); +void MifareDesfireGetInformation() { - // card select - information - if ( !iso14443a_select_card(NULL, &card, NULL, true, 0, false) ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) DbpString("Can't select card"); - OnError(1); - return; - } - - if ( card.uidlen != 7 ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen); - OnError(2); - return; - } - - memcpy(dataout, card.uid, 7); + int len = 0; + iso14a_card_select_t card; + uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00}; + uint8_t dataout[PM3_CMD_DATA_SIZE] = {0x00}; - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - uint8_t cmd[] = {GET_VERSION}; - size_t cmd_len = sizeof(cmd); - - len = DesfireAPDU(cmd, cmd_len, resp); - if ( !len ) { - print_result("ERROR <--: ", resp, len); - OnError(3); - return; - } - - LED_A_OFF(); - LED_B_ON(); - memcpy(dataout+7,resp+3,7); - - // ADDITION_FRAME 1 - cmd[0] = ADDITIONAL_FRAME; - len = DesfireAPDU(cmd, cmd_len, resp); - if ( !len ) { - print_result("ERROR <--: ", resp, len); - OnError(3); - return; - } - - LED_B_OFF(); - LED_C_ON(); - memcpy(dataout+7+7,resp+3,7); + /* + 1 = PCB 1 + 2 = cid 2 + 3 = desfire command 3 + 4-5 = crc 4 key + 5-6 crc + PCB == 0x0A because sending CID byte. + CID == 0x00 first card? + */ + clear_trace(); + set_tracing(true); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - // ADDITION_FRAME 2 - len = DesfireAPDU(cmd, cmd_len, resp); - if ( !len ) { - print_result("ERROR <--: ", resp, len); - OnError(3); - return; - } - - memcpy(dataout+7+7+7,resp+3,14); - - cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout)); - - // reset the pcb_blocknum, - pcb_blocknum = 0; - OnSuccess(); + // card select - information + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { + if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card"); + OnError(1); + return; + } + + if (card.uidlen != 7) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen); + OnError(2); + return; + } + + memcpy(dataout, card.uid, 7); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + uint8_t cmd[] = {GET_VERSION}; + size_t cmd_len = sizeof(cmd); + + len = DesfireAPDU(cmd, cmd_len, resp); + if (!len) { + print_result("ERROR <--: ", resp, len); + OnError(3); + return; + } + + LED_A_OFF(); + LED_B_ON(); + memcpy(dataout + 7, resp + 3, 7); + + // ADDITION_FRAME 1 + cmd[0] = ADDITIONAL_FRAME; + len = DesfireAPDU(cmd, cmd_len, resp); + if (!len) { + print_result("ERROR <--: ", resp, len); + OnError(3); + return; + } + + LED_B_OFF(); + LED_C_ON(); + memcpy(dataout + 7 + 7, resp + 3, 7); + + // ADDITION_FRAME 2 + len = DesfireAPDU(cmd, cmd_len, resp); + if (!len) { + print_result("ERROR <--: ", resp, len); + OnError(3); + return; + } + + memcpy(dataout + 7 + 7 + 7, resp + 3, 14); + + reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout)); + + // reset the pcb_blocknum, + pcb_blocknum = 0; + OnSuccess(); } -void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){ +void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { + // mode = arg0 + // algo = arg1 + // keyno = arg2 + int len = 0; + //uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47}; + uint8_t PICC_MASTER_KEY16[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; + //uint8_t null_key_data16[16] = {0x00}; + //uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; + //uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; - int len = 0; - //uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47}; - uint8_t PICC_MASTER_KEY16[16] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f }; - uint8_t null_key_data8[8] = {0x00}; - //uint8_t null_key_data16[16] = {0x00}; - //uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; - //uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF}; + uint8_t resp[256] = {0x00}; - uint8_t resp[256] = {0x00}; - uint8_t IV[16] = {0x00}; + size_t datalen = datain[0]; - size_t datalen = datain[0]; - - uint8_t cmd[40] = {0x00}; - uint8_t encRndB[16] = {0x00}; - uint8_t decRndB[16] = {0x00}; - uint8_t nonce[16] = {0x00}; - uint8_t both[32] = {0x00}; - uint8_t encBoth[32] = {0x00}; + uint8_t cmd[40] = {0x00}; + uint8_t encRndB[16] = {0x00}; + uint8_t decRndB[16] = {0x00}; + uint8_t both[32] = {0x00}; - InitDesfireCard(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - // 3 olika sätt att authenticera. AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) - // 4 olika crypto algo DES, 3DES, 3K3DES, AES - // 3 olika kommunikations sätt, PLAIN,MAC,CRYPTO - - // des, nyckel 0, - switch (mode){ - case 1:{ + InitDesfireCard(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + // 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32) + // 4 different crypto arg1 DES, 3DES, 3K3DES, AES + // 3 different communication modes, PLAIN,MAC,CRYPTO + + // des, key 0, + switch (arg0) { + case 1: { uint8_t keybytes[16]; uint8_t RndA[8] = {0x00}; uint8_t RndB[8] = {0x00}; - - if (algo == 2) { - if (datain[1] == 0xff){ - memcpy(keybytes,PICC_MASTER_KEY16,16); + + if (arg1 == 2) { + if (datain[1] == 0xff) { + memcpy(keybytes, PICC_MASTER_KEY16, 16); } else { - memcpy(keybytes, datain+1, datalen); + memcpy(keybytes, datain + 1, datalen); } } else { - if (algo == 1) { - if (datain[1] == 0xff){ - memcpy(keybytes,null_key_data8,8); - } else{ - memcpy(keybytes, datain+1, datalen); - } + if (arg1 == 1) { + if (datain[1] == 0xff) { + uint8_t null_key_data8[8] = {0x00}; + memcpy(keybytes, null_key_data8, 8); + } else { + memcpy(keybytes, datain + 1, datalen); + } } } - + struct desfire_key defaultkey = {0}; desfirekey_t key = &defaultkey; - - if (algo == 2) + + if (arg1 == 2) Desfire_3des_key_new_with_version(keybytes, key); - else if (algo ==1) - Desfire_des_key_new(keybytes, key); - + else if (arg1 == 1) + Desfire_des_key_new(keybytes, key); + cmd[0] = AUTHENTICATE; - cmd[1] = keyno; //keynumber + cmd[1] = arg2; //keynumber len = DesfireAPDU(cmd, 2, resp); - if ( !len ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) { + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { DbpString("Authentication failed. Card timeout."); } OnError(3); return; } - - if ( resp[2] == 0xaf ){ + + if (resp[2] == 0xaf) { } else { DbpString("Authentication failed. Invalid key number."); OnError(3); return; } - - memcpy( encRndB, resp+3, 8); - if (algo == 2) + + memcpy(encRndB, resp + 3, 8); + if (arg1 == 2) tdes_dec(&decRndB, &encRndB, key->data); - else if (algo == 1) - des_dec(&decRndB, &encRndB, key->data); - + else if (arg1 == 1) + des_dec(&decRndB, &encRndB, key->data); + memcpy(RndB, decRndB, 8); - rol(decRndB,8); - + rol(decRndB, 8); + // This should be random uint8_t decRndA[8] = {0x00}; memcpy(RndA, decRndA, 8); uint8_t encRndA[8] = {0x00}; - - if (algo == 2) + + if (arg1 == 2) tdes_dec(&encRndA, &decRndA, key->data); - else if (algo == 1) - des_dec(&encRndA, &decRndA, key->data); - + else if (arg1 == 1) + des_dec(&encRndA, &decRndA, key->data); + memcpy(both, encRndA, 8); - + for (int x = 0; x < 8; x++) { decRndB[x] = decRndB[x] ^ encRndA[x]; - + } - - if (algo == 2) + + if (arg1 == 2) tdes_dec(&encRndB, &decRndB, key->data); - else if (algo == 1) - des_dec(&encRndB, &decRndB, key->data); - + else if (arg1 == 1) + des_dec(&encRndB, &decRndB, key->data); + memcpy(both + 8, encRndB, 8); - + cmd[0] = ADDITIONAL_FRAME; - memcpy(cmd+1, both, 16 ); - + memcpy(cmd + 1, both, 16); + len = DesfireAPDU(cmd, 17, resp); - if ( !len ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) { + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { DbpString("Authentication failed. Card timeout."); } OnError(3); return; } - - if ( resp[2] == 0x00 ){ - + + if (resp[2] == 0x00) { + struct desfire_key sessionKey = {0}; desfirekey_t skey = &sessionKey; - Desfire_session_key_new( RndA, RndB , key, skey ); + Desfire_session_key_new(RndA, RndB, key, skey); //print_result("SESSION : ", skey->data, 8); - - memcpy(encRndA, resp+3, 8); - - if (algo == 2) + + memcpy(encRndA, resp + 3, 8); + + if (arg1 == 2) tdes_dec(&encRndA, &encRndA, key->data); - else if (algo == 1) - des_dec(&encRndA, &encRndA, key->data); - - rol(decRndA,8); + else if (arg1 == 1) + des_dec(&encRndA, &encRndA, key->data); + + rol(decRndA, 8); for (int x = 0; x < 8; x++) { if (decRndA[x] != encRndA[x]) { DbpString("Authentication failed. Cannot varify PICC."); @@ -315,86 +314,86 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain return; } } - + //Change the selected key to a new value. /* - + // Current key is a 3DES key, change it to a DES key - if (algo == 2) { + if (arg1 == 2) { cmd[0] = CHANGE_KEY; - cmd[1] = keyno; - + cmd[1] = arg2; + uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}; - + uint8_t first, second; uint8_t buff1[8] = {0x00}; uint8_t buff2[8] = {0x00}; uint8_t buff3[8] = {0x00}; - + memcpy(buff1,newKey, 8); memcpy(buff2,newKey + 8, 8); - + compute_crc(CRC_14443_A, newKey, 16, &first, &second); memcpy(buff3, &first, 1); memcpy(buff3 + 1, &second, 1); - + tdes_dec(&buff1, &buff1, skey->data); memcpy(cmd+2,buff1,8); - + for (int x = 0; x < 8; x++) { buff2[x] = buff2[x] ^ buff1[x]; } tdes_dec(&buff2, &buff2, skey->data); memcpy(cmd+10,buff2,8); - + for (int x = 0; x < 8; x++) { buff3[x] = buff3[x] ^ buff2[x]; } tdes_dec(&buff3, &buff3, skey->data); memcpy(cmd+18,buff3,8); - + // The command always times out on the first attempt, this will retry until a response // is recieved. len = 0; while(!len) { len = DesfireAPDU(cmd,26,resp); } - + } else { // Current key is a DES key, change it to a 3DES key - if (algo == 1) { + if (arg1 == 1) { cmd[0] = CHANGE_KEY; - cmd[1] = keyno; - + cmd[1] = arg2; + uint8_t newKey[16] = {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; - + uint8_t first, second; uint8_t buff1[8] = {0x00}; uint8_t buff2[8] = {0x00}; uint8_t buff3[8] = {0x00}; - + memcpy(buff1,newKey, 8); memcpy(buff2,newKey + 8, 8); - + compute_crc(CRC_14443_A, newKey, 16, &first, &second); memcpy(buff3, &first, 1); memcpy(buff3 + 1, &second, 1); - + des_dec(&buff1, &buff1, skey->data); memcpy(cmd+2,buff1,8); - + for (int x = 0; x < 8; x++) { buff2[x] = buff2[x] ^ buff1[x]; } des_dec(&buff2, &buff2, skey->data); memcpy(cmd+10,buff2,8); - + for (int x = 0; x < 8; x++) { buff3[x] = buff3[x] ^ buff2[x]; } des_dec(&buff3, &buff3, skey->data); memcpy(cmd+18,buff3,8); - + // The command always times out on the first attempt, this will retry until a response // is recieved. len = 0; @@ -404,168 +403,170 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain } } */ - + OnSuccess(); - if (algo == 2) - cmd_send(CMD_ACK,1,0,0,skey->data,16); - else if (algo == 1) - cmd_send(CMD_ACK,1,0,0,skey->data,8); + if (arg1 == 2) + reply_old(CMD_ACK, 1, 0, 0, skey->data, 16); + else if (arg1 == 1) + reply_old(CMD_ACK, 1, 0, 0, skey->data, 8); } else { DbpString("Authentication failed."); OnError(6); return; } + } + break; + case 2: + //SendDesfireCommand(AUTHENTICATE_ISO, &arg2, resp); + break; + case 3: { + + //defaultkey + uint8_t keybytes[16] = {0x00}; + if (datain[1] == 0xff) { + memcpy(keybytes, PICC_MASTER_KEY16, 16); + } else { + memcpy(keybytes, datain + 1, datalen); } - break; - case 2: - //SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp); - break; - case 3:{ - - //defaultkey - uint8_t keybytes[16] = {0x00}; - if (datain[1] == 0xff){ - memcpy(keybytes,PICC_MASTER_KEY16,16); - } else{ - memcpy(keybytes, datain+1, datalen); - } - - struct desfire_key defaultkey = {0x00}; - desfirekey_t key = &defaultkey; - Desfire_aes_key_new( keybytes, key); - - AesCtx ctx; - if ( AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0 ){ - if( MF_DBGLEVEL >= 4) { - DbpString("AES context failed to init"); - } - OnError(7); - return; - } - - cmd[0] = AUTHENTICATE_AES; - cmd[1] = 0x00; //keynumber - len = DesfireAPDU(cmd, 2, resp); - if ( !len ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } - OnError(3); - return; - } - - memcpy( encRndB, resp+3, 16); - - // dekryptera tagnonce. - AesDecrypt(&ctx, encRndB, decRndB, 16); - rol(decRndB,16); - memcpy(both, nonce,16); - memcpy(both+16, decRndB ,16 ); - AesEncrypt(&ctx, both, encBoth, 32 ); - - cmd[0] = ADDITIONAL_FRAME; - memcpy(cmd+1, encBoth, 32 ); - - len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33 - if ( !len ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) { - DbpString("Authentication failed. Card timeout."); - } + + struct desfire_key defaultkey = {0x00}; + desfirekey_t key = &defaultkey; + Desfire_aes_key_new(keybytes, key); + + AesCtx ctx; + uint8_t IV[16] = {0x00}; + if (AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0) { + if (DBGLEVEL >= 4) { + DbpString("AES context failed to init"); + } + OnError(7); + return; + } + + cmd[0] = AUTHENTICATE_AES; + cmd[1] = 0x00; //keynumber + len = DesfireAPDU(cmd, 2, resp); + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { + DbpString("Authentication failed. Card timeout."); + } OnError(3); - return; - } - - if ( resp[2] == 0x00 ){ - // Create AES Session key - struct desfire_key sessionKey = {0}; - desfirekey_t skey = &sessionKey; - Desfire_session_key_new( nonce, decRndB , key, skey ); - print_result("SESSION : ", skey->data, 16); - } else { - DbpString("Authentication failed."); - OnError(7); - return; - } - - break; - } - } - - OnSuccess(); - cmd_send(CMD_ACK,1,len,0,resp,len); + return; + } + + memcpy(encRndB, resp + 3, 16); + + // dekryptera tagnonce. + AesDecrypt(&ctx, encRndB, decRndB, 16); + rol(decRndB, 16); + uint8_t nonce[16] = {0x00}; + memcpy(both, nonce, 16); + memcpy(both + 16, decRndB, 16); + uint8_t encBoth[32] = {0x00}; + AesEncrypt(&ctx, both, encBoth, 32); + + cmd[0] = ADDITIONAL_FRAME; + memcpy(cmd + 1, encBoth, 32); + + len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33 + if (!len) { + if (DBGLEVEL >= DBG_ERROR) { + DbpString("Authentication failed. Card timeout."); + } + OnError(3); + return; + } + + if (resp[2] == 0x00) { + // Create AES Session key + struct desfire_key sessionKey = {0}; + desfirekey_t skey = &sessionKey; + Desfire_session_key_new(nonce, decRndB, key, skey); + print_result("SESSION : ", skey->data, 16); + } else { + DbpString("Authentication failed."); + OnError(7); + return; + } + + break; + } + } + + OnSuccess(); + reply_old(CMD_ACK, 1, len, 0, resp, len); } -// 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO) +// 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO) // cmd = cmd bytes to send // cmd_len = length of cmd // dataout = pointer to response data array -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){ +int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) { - size_t len = 0; - size_t wrappedLen = 0; - uint8_t wCmd[USB_CMD_DATA_SIZE] = {0x00}; - uint8_t resp[MAX_FRAME_SIZE]; + size_t len = 0; + size_t wrappedLen = 0; + uint8_t wCmd[PM3_CMD_DATA_SIZE] = {0x00}; + uint8_t resp[MAX_FRAME_SIZE]; uint8_t par[MAX_PARITY_SIZE]; - - wrappedLen = CreateAPDU( cmd, cmd_len, wCmd); - - if (MF_DBGLEVEL >= 4) - print_result("WCMD <--: ", wCmd, wrappedLen); - ReaderTransmit( wCmd, wrappedLen, NULL); + wrappedLen = CreateAPDU(cmd, cmd_len, wCmd); - len = ReaderReceive(resp, par); - if ( !len ) { - if (MF_DBGLEVEL >= 4) Dbprintf("fukked"); - return false; //DATA LINK ERROR - } - // if we received an I- or R(ACK)-Block with a block number equal to the - // current block number, toggle the current block number - else if (len >= 4 // PCB+CID+CRC = 4 bytes - && ((resp[0] & 0xC0) == 0 // I-Block - || (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 - && (resp[0] & 0x01) == pcb_blocknum) // equal block numbers - { - pcb_blocknum ^= 1; //toggle next block - } + if (DBGLEVEL >= 4) + print_result("WCMD <--: ", wCmd, wrappedLen); - memcpy(dataout, resp, len); - return len; -} + ReaderTransmit(wCmd, wrappedLen, NULL); + + len = ReaderReceive(resp, par); + if (!len) { + if (DBGLEVEL >= 4) Dbprintf("fukked"); + return false; //DATA LINK ERROR + } + // if we received an I- or R(ACK)-Block with a block number equal to the + // current block number, toggle the current block number + else if (len >= 4 // PCB+CID+CRC = 4 bytes + && ((resp[0] & 0xC0) == 0 // I-Block + || (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers + pcb_blocknum ^= 1; //toggle next block + } + + memcpy(dataout, resp, len); + return len; +} // CreateAPDU -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout){ - - size_t cmdlen = MIN(len+4, USB_CMD_DATA_SIZE-1); +size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) { - uint8_t cmd[cmdlen]; - memset(cmd, 0, cmdlen); - - cmd[0] = 0x0A; // 0x0A = skicka cid, 0x02 = ingen cid. Särskilda bitar // - cmd[0] |= pcb_blocknum; // OR the block number into the PCB - cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards - - memcpy(cmd+2, datain, len); - AddCrc14A(cmd, len+2); - - memcpy(dataout, cmd, cmdlen); - - return cmdlen; + size_t cmdlen = MIN(len + 4, PM3_CMD_DATA_SIZE - 1); + + uint8_t cmd[cmdlen]; + memset(cmd, 0, cmdlen); + + cmd[0] = 0x0A; // 0x0A = send cid, 0x02 = no cid. + cmd[0] |= pcb_blocknum; // OR the block number into the PCB + cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards + + memcpy(cmd + 2, datain, len); + AddCrc14A(cmd, len + 2); + + memcpy(dataout, cmd, cmdlen); + + return cmdlen; } - // crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */ - // crc_update(&desfire_crc32, addr, addr_sz); - // crc_update(&desfire_crc32, byte, 8); - // uint32_t crc = crc_finish(&desfire_crc32); +// crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */ +// crc_update(&desfire_crc32, addr, addr_sz); +// crc_update(&desfire_crc32, byte, 8); +// uint32_t crc = crc_finish(&desfire_crc32); -void OnSuccess(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - mifare_ultra_halt(); - switch_off(); +void OnSuccess() { + pcb_blocknum = 0; + ReaderTransmit(deselect_cmd, 3, NULL); + mifare_ultra_halt(); + switch_off(); } -void OnError(uint8_t reason){ - cmd_send(CMD_ACK,0,reason,0,0,0); - OnSuccess(); +void OnError(uint8_t reason) { + reply_old(CMD_ACK, 0, reason, 0, 0, 0); + OnSuccess(); } diff --git a/armsrc/mifaredesfire.h b/armsrc/mifaredesfire.h index 40c623ef9..7547dfcb2 100644 --- a/armsrc/mifaredesfire.h +++ b/armsrc/mifaredesfire.h @@ -6,7 +6,6 @@ #include "apps.h" #include "string.h" #include "BigBuf.h" -#include "iso14443crc.h" #include "iso14443a.h" #include "desfire_key.h" #include "mifareutil.h" diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c new file mode 100644 index 000000000..714beb284 --- /dev/null +++ b/armsrc/mifaresim.c @@ -0,0 +1,1199 @@ +//----------------------------------------------------------------------------- +// 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 +//----------------------------------------------------------------------------- + +// Verbose Mode: +// DBG_NONE 0 +// DBG_ERROR 1 +// DBG_INFO 2 +// DBG_DEBUG 3 +// DBG_EXTENDED 4 + +// /!\ Printing Debug message is disrupting emulation, +// Only use with caution during debugging + + +#include "iso14443a.h" +#include "mifaresim.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 "cmd.h" +#include "protocols.h" +#include "apps.h" + +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: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_KEYA_READ"); + return false; + } + case AC_KEYA_WRITE: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_KEYA_WRITE"); + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + } + case AC_KEYB_READ: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_KEYB_READ"); + return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01)); + } + case AC_KEYB_WRITE: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_KEYB_WRITE"); + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04)) + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + } + case AC_AC_READ: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_AC_READ"); + return ((keytype == AUTHKEYA) + || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + } + case AC_AC_WRITE: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsTrailerAccessAllowed: AC_AC_WRITE"); + return ((keytype == AUTHKEYA && (AC == 0x01)) + || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); + } + 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 <= MIFARE_2K_MAXBLOCK) { + 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); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed: case 0x00 - %02x", AC); + break; + } + case 0x01: { + AC = ((sector_trailer[7] >> 3) & 0x04) + | ((sector_trailer[8] >> 0) & 0x02) + | ((sector_trailer[8] >> 5) & 0x01); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed: case 0x01 - %02x", AC); + break; + } + case 0x02: { + AC = ((sector_trailer[7] >> 4) & 0x04) + | ((sector_trailer[8] >> 1) & 0x02) + | ((sector_trailer[8] >> 6) & 0x01); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed: case 0x02 - %02x", AC); + break; + } + default: + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed: Error"); + return false; + } + + switch (action) { + case AC_DATA_READ: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed - AC_DATA_READ: OK"); + return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) + || (keytype == AUTHKEYB && !(AC == 0x07))); + } + case AC_DATA_WRITE: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed - AC_DATA_WRITE: OK"); + return ((keytype == AUTHKEYA && (AC == 0x00)) + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); + } + case AC_DATA_INC: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("IsDataAccessAllowed - AC_DATA_INC: OK"); + return ((keytype == AUTHKEYA && (AC == 0x00)) + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); + } + case AC_DATA_DEC_TRANS_REST: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("AC_DATA_DEC_TRANS_REST: OK"); + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); + } + } + + 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 bool MifareSimInit(uint16_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) { + + // SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf + // ATQA + static uint8_t rATQA_Mini[] = {0x04, 0x00}; // indicate Mifare classic Mini 4Byte UID + static uint8_t rATQA_1k[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID + static uint8_t rATQA_2k[] = {0x04, 0x00}; // indicate Mifare classic 2k 4Byte UID + static uint8_t rATQA_4k[] = {0x02, 0x00}; // indicate Mifare classic 4k 4Byte UID + + // SAK + static uint8_t rSAK_Mini = 0x09; // mifare Mini + static uint8_t rSAK_1k = 0x08; // mifare 1k + static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support + static uint8_t rSAK_4k = 0x18; // mifare 4k + + static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level + static uint8_t rUIDBCC1b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level, last 4 bytes + static uint8_t rUIDBCC1b3[] = {0x00, 0x00, 0x00}; // UID 1st cascade level, last 3 bytes + static uint8_t rUIDBCC1b2[] = {0x00, 0x00}; // UID 1st cascade level, last 2 bytes + static uint8_t rUIDBCC1b1[] = {0x00}; // UID 1st cascade level, last byte + static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level + static uint8_t rUIDBCC2b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 2st cascade level, last 4 bytes + static uint8_t rUIDBCC2b3[] = {0x00, 0x00, 0x00}; // UID 2st cascade level, last 3 bytes + static uint8_t rUIDBCC2b2[] = {0x00, 0x00}; // UID 2st cascade level, last 2 bytes + static uint8_t rUIDBCC2b1[] = {0x00}; // UID 2st cascade level, last byte + static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level + static uint8_t rUIDBCC3b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 3st cascade level, last 4 bytes + static uint8_t rUIDBCC3b3[] = {0x00, 0x00, 0x00}; // UID 3st cascade level, last 3 bytes + static uint8_t rUIDBCC3b2[] = {0x00, 0x00}; // UID 3st cascade level, last 2 bytes + static uint8_t rUIDBCC3b1[] = {0x00}; // UID 3st cascade level, last byte + + static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA + static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC + static uint8_t rSAKuid[] = {0x04, 0xda, 0x17}; // UID incomplete cascade bit, CRC + + // RATS answer for 2K NXP mifare classic (with CRC) + static uint8_t rRATS[] = {0x0c, 0x75, 0x77, 0x80, 0x02, 0xc1, 0x05, 0x2f, 0x2f, 0x01, 0xbc, 0xd6, 0x60, 0xd3}; + + *uid_len = 0; + + // By default use 1K tag + memcpy(rATQA, rATQA_1k, sizeof(rATQA)); + rSAK[0] = rSAK_1k; + + //by default RATS not supported + *rats_len = 0; + *rats = NULL; + + // -- Determine the UID + // Can be set from emulator memory or incoming data + // Length: 4,7,or 10 bytes + + // Get UID, SAK, ATQA from EMUL + if ((flags & FLAG_UID_IN_EMUL) == FLAG_UID_IN_EMUL) { + uint8_t block0[16]; + emlGetMemBt(block0, 0, 16); + + // If uid size defined, copy only uid from EMUL to use, backward compatibility for 'hf_colin.c', 'hf_mattyrun.c' + if ((flags & (FLAG_4B_UID_IN_DATA | FLAG_7B_UID_IN_DATA | FLAG_10B_UID_IN_DATA)) != 0) { + memcpy(datain, block0, 10); // load 10bytes from EMUL to the datain pointer. to be used below. + } else { + // Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA + if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) { + flags |= FLAG_4B_UID_IN_DATA; + memcpy(datain, block0, 4); + rSAK[0] = block0[5]; + memcpy(rATQA, &block0[6], sizeof(rATQA)); + } + // Check for 7 bytes UID: double size uid bits in ATQA + else if ((block0[8] & 0xc0) == 0x40) { + flags |= FLAG_7B_UID_IN_DATA; + memcpy(datain, block0, 7); + rSAK[0] = block0[7]; + memcpy(rATQA, &block0[8], sizeof(rATQA)); + } else { + Dbprintf("[-] ERROR: Invalid dump. UID/SAK/ATQA not found"); + return false; + } + } + + } + + // Tune tag type, if defined directly + // Otherwise use defined by default or extracted from EMUL + if ((flags & FLAG_MF_MINI) == FLAG_MF_MINI) { + memcpy(rATQA, rATQA_Mini, sizeof(rATQA)); + rSAK[0] = rSAK_Mini; + Dbprintf("Mifare Mini"); + } else if ((flags & FLAG_MF_1K) == FLAG_MF_1K) { + memcpy(rATQA, rATQA_1k, sizeof(rATQA)); + rSAK[0] = rSAK_1k; + Dbprintf("Mifare 1K"); + } else if ((flags & FLAG_MF_2K) == FLAG_MF_2K) { + memcpy(rATQA, rATQA_2k, sizeof(rATQA)); + rSAK[0] = rSAK_2k; + *rats = rRATS; + *rats_len = sizeof(rRATS); + Dbprintf("Mifare 2K with RATS support"); + } else if ((flags & FLAG_MF_4K) == FLAG_MF_4K) { + memcpy(rATQA, rATQA_4k, sizeof(rATQA)); + rSAK[0] = rSAK_4k; + Dbprintf("Mifare 4K"); + } + + // Prepare UID arrays + if ((flags & FLAG_4B_UID_IN_DATA) == FLAG_4B_UID_IN_DATA) { // get UID from datain + memcpy(rUIDBCC1, datain, 4); + *uid_len = 4; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_4B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_4B_UID_IN_DATA, flags, rUIDBCC1); + + + // save CUID + *cuid = bytes_to_num(rUIDBCC1, 4); + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + if (DBGLEVEL >= DBG_NONE) { + Dbprintf("4B UID: %02x%02x%02x%02x", rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x00; // single size uid + + } else if ((flags & FLAG_7B_UID_IN_DATA) == FLAG_7B_UID_IN_DATA) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(rUIDBCC2, datain + 3, 4); + *uid_len = 7; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_7B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_7B_UID_IN_DATA, flags, rUIDBCC1); + + // save CUID + *cuid = bytes_to_num(rUIDBCC2, 4); + // CascadeTag, CT + rUIDBCC1[0] = MIFARE_SELECT_CT; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (DBGLEVEL >= DBG_NONE) { + Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3]); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x40; // double size uid + + } else if ((flags & FLAG_10B_UID_IN_DATA) == FLAG_10B_UID_IN_DATA) { + memcpy(&rUIDBCC1[1], datain, 3); + memcpy(&rUIDBCC2[1], datain + 3, 3); + memcpy(rUIDBCC3, datain + 6, 4); + *uid_len = 10; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MifareSimInit - FLAG_10B_UID_IN_DATA => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_10B_UID_IN_DATA, flags, rUIDBCC1); + + // save CUID + *cuid = bytes_to_num(rUIDBCC3, 4); + // CascadeTag, CT + rUIDBCC1[0] = MIFARE_SELECT_CT; + rUIDBCC2[0] = MIFARE_SELECT_CT; + // BCC + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3]; + + if (DBGLEVEL >= DBG_NONE) { + Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], + rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3], + rUIDBCC3[0], rUIDBCC3[1], rUIDBCC3[2], rUIDBCC3[3] + ); + } + + // Correct uid size bits in ATQA + rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid + } else { + Dbprintf("[-] ERROR: UID size not defined"); + return false; + } + + // clone UIDs for byte-frame anti-collision multiple tag selection procedure + memcpy(rUIDBCC1b4, &rUIDBCC1[1], 4); + memcpy(rUIDBCC1b3, &rUIDBCC1[2], 3); + memcpy(rUIDBCC1b2, &rUIDBCC1[3], 2); + memcpy(rUIDBCC1b1, &rUIDBCC1[4], 1); + if (*uid_len >= 7) { + memcpy(rUIDBCC2b4, &rUIDBCC2[1], 4); + memcpy(rUIDBCC2b3, &rUIDBCC2[2], 3); + memcpy(rUIDBCC2b2, &rUIDBCC2[3], 2); + memcpy(rUIDBCC2b1, &rUIDBCC2[4], 1); + } + if (*uid_len == 10) { + memcpy(rUIDBCC3b4, &rUIDBCC3[1], 4); + memcpy(rUIDBCC3b3, &rUIDBCC3[2], 3); + memcpy(rUIDBCC3b2, &rUIDBCC3[3], 2); + memcpy(rUIDBCC3b1, &rUIDBCC3[4], 1); + } + + // Calculate actual CRC + AddCrc14A(rSAK, sizeof(rSAK) - 2); + +#define TAG_RESPONSE_COUNT 18 + static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { + { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type + { .response = rSAK, .response_n = sizeof(rSAK) }, // + { .response = rSAKuid, .response_n = sizeof(rSAKuid) }, // + // Do not reorder. Block used via relative index of rUIDBCC1 + { .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid + { .response = rUIDBCC1b4, .response_n = sizeof(rUIDBCC1b4)}, + { .response = rUIDBCC1b3, .response_n = sizeof(rUIDBCC1b3)}, + { .response = rUIDBCC1b2, .response_n = sizeof(rUIDBCC1b2)}, + { .response = rUIDBCC1b1, .response_n = sizeof(rUIDBCC1b1)}, + // Do not reorder. Block used via relative index of rUIDBCC2 + { .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid + { .response = rUIDBCC2b4, .response_n = sizeof(rUIDBCC2b4)}, + { .response = rUIDBCC2b3, .response_n = sizeof(rUIDBCC2b3)}, + { .response = rUIDBCC2b2, .response_n = sizeof(rUIDBCC2b2)}, + { .response = rUIDBCC2b1, .response_n = sizeof(rUIDBCC2b1)}, + // Do not reorder. Block used via relative index of rUIDBCC3 + { .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid + { .response = rUIDBCC3b4, .response_n = sizeof(rUIDBCC3b4)}, + { .response = rUIDBCC3b3, .response_n = sizeof(rUIDBCC3b3)}, + { .response = rUIDBCC3b2, .response_n = sizeof(rUIDBCC3b2)}, + { .response = rUIDBCC3b1, .response_n = sizeof(rUIDBCC3b1)} + }; + + // 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 18 predefined responses with a total of 53 bytes data to transmit. + // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) + // 53 * 8 data bits, 53 * 1 parity bits, 18 start bits, 18 stop bits, 18 correction bits -> need 571 bytes buffer +#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 571 + + uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); + // modulation buffer pointer and current buffer free space size + uint8_t *free_buffer_pointer = free_buffer; + size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; + + for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) { + if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) { + Dbprintf("Not enough modulation buffer size, exit after %d elements", i); + return false; + } + } + + *responses = responses_init; + + // indices into responses array: +#define ATQA 0 +#define SAK 1 +#define SAKuid 2 +#define UIDBCC1 3 +#define UIDBCC2 8 +#define UIDBCC3 13 + + return true; +} + + +/** +*MIFARE 1K 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_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished +* 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 infinite ... +* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) +*/ +void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain) { + tag_response_info_t *responses; + uint8_t cardSTATE = MFEMUL_NOFIELD; + uint8_t uid_len = 0; // 4,7, 10 + uint32_t cuid = 0; + + int vHf = 0; // in mV + + uint32_t selTimer = 0; + uint32_t authTimer = 0; + + uint8_t blockNo; + + uint32_t nr; + uint32_t ar; + + bool encrypted_data; + + uint8_t cardWRBL = 0; + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication + uint32_t cardRr = 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 reads a block + uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE] = {0x00}; + uint16_t receivedCmd_len; + + uint8_t response[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t response_par[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + uint8_t *rats = NULL; + uint8_t rats_len = 0; + + uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; + + //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 + uint8_t rAUTH_NT[4]; + uint8_t rAUTH_NT_keystream[4]; + uint32_t nonce = 0; + + tUart *uart = GetUart(); + + // free eventually allocated BigBuf memory but keep Emulator Memory + BigBuf_free_keep_EM(); + + if (MifareSimInit(flags, datain, &responses, &cuid, &uid_len, &rats, &rats_len) == false) { + BigBuf_free_keep_EM(); + return; + } + + // 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); + LED_D_ON(); + ResetSspClk(); + + bool finished = false; + bool button_pushed = BUTTON_PRESS(); + + while (!button_pushed && !finished && !data_available()) { + WDT_HIT(); + + // find reader field + if (cardSTATE == MFEMUL_NOFIELD) { + vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF)) >> 10; + if (vHf > MF_MINFIELDV) { + cardSTATE_TO_IDLE(); + LED_A_ON(); + } + button_pushed = BUTTON_PRESS(); + continue; + } + + //Now, get data + int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); + + if (res == 2) { //Field is off! + LEDsoff(); + cardSTATE = MFEMUL_NOFIELD; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("cardSTATE = MFEMUL_NOFIELD"); + continue; + } else if (res == 1) { // button pressed + button_pushed = true; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Button pressed"); + 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)) { + selTimer = GetTickCount(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("EmSendPrecompiledCmd(&responses[ATQA]);"); + EmSendPrecompiledCmd(&responses[ATQA]); + + // init crypto block + crypto1_destroy(pcs); + cardAUTHKEY = AUTHKEYNONE; + nonce = prng_successor(selTimer, 32); + // prepare NT for nested authentication + num_to_bytes(nonce, 4, rAUTH_NT); + num_to_bytes(cuid ^ nonce, 4, rAUTH_NT_keystream); + + LED_B_OFF(); + LED_C_OFF(); + cardSTATE = MFEMUL_SELECT; + continue; + } + + switch (cardSTATE) { + case MFEMUL_NOFIELD: + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MFEMUL_NOFIELD"); + case MFEMUL_HALTED: + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MFEMUL_HALTED"); + case MFEMUL_IDLE: { + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MFEMUL_IDLE"); + break; + } + + // The anti-collision sequence, which is a mandatory part of the card activation sequence. + // It auto with 4-byte UID (= Single Size UID), + // 7 -byte UID (= Double Size UID) or 10-byte UID (= Triple Size UID). + // For details see chapter 2 of AN10927.pdf + // + // This case is used for all Cascade Levels, because: + // 1) Any devices (under Android for example) after full select procedure completed, + // when UID is known, uses "fast-selection" method. In this case reader ignores + // first cascades and tries to select tag by last bytes of UID of last cascade + // 2) Any readers (like ACR122U) uses bit oriented anti-collision frames during selectin, + // same as multiple tags. For details see chapter 6.1.5.3 of ISO/IEC 14443-3 + case MFEMUL_SELECT: { + int uid_index = -1; + // Extract cascade level + if (receivedCmd_len >= 2) { + switch (receivedCmd[0]) { + case ISO14443A_CMD_ANTICOLL_OR_SELECT: + uid_index = UIDBCC1; + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: + uid_index = UIDBCC2; + break; + case ISO14443A_CMD_ANTICOLL_OR_SELECT_3: + uid_index = UIDBCC3; + break; + } + } + if (uid_index < 0) { + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] Incorrect cascade level received"); + break; + } + + // Incoming SELECT ALL for any cascade level + if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) { + EmSendPrecompiledCmd(&responses[uid_index]); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ALL - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); + break; + } + + // Incoming SELECT CLx for any cascade level + if (receivedCmd_len == 9 && receivedCmd[1] == 0x70) { + if (memcmp(&receivedCmd[2], responses[uid_index].response, 4) == 0) { + bool cl_finished = (uid_len == 4 && uid_index == UIDBCC1) || + (uid_len == 7 && uid_index == UIDBCC2) || + (uid_len == 10 && uid_index == UIDBCC3); + EmSendPrecompiledCmd(&responses[cl_finished ? SAK : SAKuid]); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT CLx %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]); + if (cl_finished) { + LED_B_ON(); + cardSTATE = MFEMUL_WORK; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_WORK"); + } + } else { + // IDLE, not our UID + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE"); + } + break; + } + + // Incoming anti-collision frame + if (receivedCmd_len >= 2 && receivedCmd_len <= 6 && receivedCmd[1] == 0x50) { + // we can process only full-byte frame anti-collision procedure + if (memcmp(&receivedCmd[2], responses[uid_index].response, receivedCmd_len - 2) == 0) { + // response missing part of UID via relative array index + EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); + } else { + // IDLE, not our UID or split-byte frame anti-collision (not supports) + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] cardSTATE = MFEMUL_IDLE"); + } + break; + } + + // Unknown selection procedure + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE_TO_IDLE(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_SELECT] Unknown selection procedure"); + break; + } + + // WORK + case MFEMUL_WORK: { + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Enter in case"); + + if (receivedCmd_len == 0) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] NO CMD received"); + break; + } + + encrypted_data = (cardAUTHKEY != AUTHKEYNONE); + if (encrypted_data) { + // decrypt seqence + mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Decrypt seqence"); + } else { + // Data in clear + memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len); + } + + if (!CheckCrc14A(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd_dec, receivedCmd_len); + break; + } + + if (receivedCmd_len == 4 && (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB)) { + + // Reader asks for AUTH: 6X XX + // RCV: 60 XX => Using KEY A + // RCV: 61 XX => Using KEY B + // XX: Block number + + // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack + if (receivedCmd_dec[1] > MIFARE_4K_MAXBLOCK && !((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (DBGLEVEL >= 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; + } + + authTimer = GetTickCount(); + + // received block num -> sector + // Example: 6X [00] + // 4K tags have 16 blocks per sector 32..39 + cardAUTHSC = MifareBlockToSector(receivedCmd_dec[1]); + + // cardAUTHKEY: 60 => Auth use Key A + // cardAUTHKEY: 61 => Auth use Key B + cardAUTHKEY = receivedCmd_dec[0] & 0x01; + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] KEY %c: %012" PRIx64, (cardAUTHKEY == 0) ? 'A' : 'B', emlGetKey(cardAUTHSC, cardAUTHKEY)); + + // first authentication + crypto1_destroy(pcs); + + // Load key into crypto + crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); + + if (!encrypted_data) { + // Receive Cmd in clear txt + // Update crypto state (UID ^ NONCE) + crypto1_word(pcs, cuid ^ nonce, 0); + // rAUTH_NT contains prepared nonce for authenticate + EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Reader authenticating for block %d (0x%02x) with key %c - nonce: %02X - ciud: %02X", receivedCmd_dec[1], receivedCmd_dec[1], (cardAUTHKEY == 0) ? 'A' : 'B', rAUTH_AT, cuid); + } else { + // nested authentication + /* + ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0); + num_to_bytes(ans, 4, rAUTH_AT); + */ + // rAUTH_NT, rAUTH_NT_keystream contains prepared nonce and keystream for nested authentication + // we need calculate parity bits for non-encrypted sequence + mf_crypto1_encryptEx(pcs, rAUTH_NT, rAUTH_NT_keystream, response, 4, response_par); + EmSendCmdPar(response, 4, response_par); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Reader doing nested authentication for block %d (0x%02x) with key %c", receivedCmd_dec[1], receivedCmd_dec[1], (cardAUTHKEY == 0) ? 'A' : 'B'); + } + + cardSTATE = MFEMUL_AUTH1; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_AUTH1 - rAUTH_NT: %02X", rAUTH_NT); + break; + } + + // rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued + // BUT... ACK --> NACK + if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) { + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + break; + } + + // rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK) + if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) { + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_ACK) : CARD_ACK); + break; + } + + // case MFEMUL_WORK => if Cmd is Read, Write, Inc, Dec, Restore, Transfert + if (receivedCmd_len == 4 && (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK + || receivedCmd_dec[0] == ISO14443A_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)) { + // all other commands must be encrypted (authenticated) + if (!encrypted_data) { + EmSend4bit(CARD_NACK_NA); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Commands must be encrypted (authenticated)"); + break; + } + // Check if Block num is not too far + if (receivedCmd_dec[1] > MIFARE_4K_MAXBLOCK) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] 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 (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); + break; + } + } + + // case MFEMUL_WORK => CMD READ block + if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { + blockNo = receivedCmd_dec[1]; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Reader reading block %d (0x%02x)", blockNo, blockNo); + emlGetMem(response, blockNo, 1); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[MFEMUL_WORK - ISO14443A_CMD_READBLOCK] Data Block[%d]: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", blockNo, + response[0], response[1], response[2], response[3], response[4], response[5], response[6], + response[7], response[8], response[9], response[10], response[11], response[12], response[13], + response[14], response[15]); + } + + // Access permission managment: + // + // Sector Trailer: + // - KEY A access + // - KEY B access + // - AC bits access + // + // Data block: + // - Data access + + // If permission is not allowed, data is cleared (00) in emulator memeory. + // ex: a0a1a2a3a4a561e789c1b0b1b2b3b4b5 => 00000000000061e789c1b0b1b2b3b4b5 + + + // Check if selected Block is a Sector Trailer + if (IsSectorTrailer(blockNo)) { + + if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYA_READ)) { + memset(response, 0x00, 6); // keyA can never be read + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyA can never be read - block %d (0x%02x)", blockNo, blockNo); + } + if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) { + memset(response + 10, 0x00, 6); // keyB cannot be read + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyB cannot be read - block %d (0x%02x)", blockNo, blockNo); + } + if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) { + memset(response + 6, 0x00, 4); // AC bits cannot be read + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] AC bits cannot be read - block %d (0x%02x)", blockNo, blockNo); + } + } else { + if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) { + memset(response, 0x00, 16); // datablock cannot be read + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] Data block %d (0x%02x) cannot be read", blockNo, blockNo); + } + } + AddCrc14A(response, 16); + mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par); + EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par); + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[MFEMUL_WORK - EmSendCmdPar] Data Block[%d]: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", blockNo, + response[0], response[1], response[2], response[3], response[4], response[5], response[6], + response[7], response[8], response[9], response[10], response[11], response[12], response[13], + response[14], response[15]); + } + numReads++; + + if (exitAfterNReads > 0 && numReads == exitAfterNReads) { + Dbprintf("[MFEMUL_WORK] %d reads done, exiting", numReads); + finished = true; + } + break; + + } // End receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK + + // case MFEMUL_WORK => CMD WRITEBLOCK + if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { + blockNo = receivedCmd_dec[1]; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0xA0 write block %d (%02x)", blockNo, blockNo); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + cardWRBL = blockNo; + cardSTATE = MFEMUL_WRITEBL2; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_WRITEBL2"); + break; + } + + // case MFEMUL_WORK => CMD INC/DEC/REST + if (receivedCmd_len == 4 && (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE)) { + blockNo = receivedCmd_dec[1]; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)", receivedCmd_dec[0], blockNo, blockNo); + if (emlCheckValBl(blockNo)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] 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)); + cardWRBL = blockNo; + + // INC + if (receivedCmd_dec[0] == MIFARE_CMD_INC) { + cardSTATE = MFEMUL_INTREG_INC; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_INTREG_INC"); + } + + // DEC + if (receivedCmd_dec[0] == MIFARE_CMD_DEC) { + cardSTATE = MFEMUL_INTREG_DEC; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_INTREG_DEC"); + } + + // REST + if (receivedCmd_dec[0] == MIFARE_CMD_RESTORE) { + cardSTATE = MFEMUL_INTREG_REST; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_INTREG_REST"); + } + break; + + } // End case MFEMUL_WORK => CMD INC/DEC/REST + + + // case MFEMUL_WORK => CMD TRANSFER + if (receivedCmd_len == 4 && receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { + blockNo = receivedCmd_dec[1]; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0x%02x transfer block %d (%02x)", receivedCmd_dec[0], blockNo, blockNo); + if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1])) + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + else + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + break; + } + + // case MFEMUL_WORK => CMD HALT + if (receivedCmd_len > 1 && receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + LED_B_OFF(); + LED_C_OFF(); + cardSTATE = MFEMUL_HALTED; + cardAUTHKEY = AUTHKEYNONE; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_HALTED"); + break; + } + + // case MFEMUL_WORK => CMD RATS + if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && receivedCmd_dec[1] == 0x80) { + if (rats && rats_len) { + if (encrypted_data) { + memcpy(response, rats, rats_len); + mf_crypto1_encrypt(pcs, response, rats_len, response_par); + EmSendCmdPar(response, rats_len, response_par); + } else + EmSendCmd(rats, rats_len); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => ACK"); + } else { + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => NACK"); + } + break; + } + + // case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT + if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) { + if (rats && rats_len) { + // response back NXP_DESELECT + if (encrypted_data) { + memcpy(response, receivedCmd_dec, receivedCmd_len); + mf_crypto1_encrypt(pcs, response, receivedCmd_len, response_par); + EmSendCmdPar(response, receivedCmd_len, response_par); + } else + EmSendCmd(receivedCmd_dec, receivedCmd_len); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK"); + } else { + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK"); + } + break; + } + + // case MFEMUL_WORK => command not allowed + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Received command not allowed, nacking"); + EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + break; + } + + // AUTH1 + case MFEMUL_AUTH1: { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_AUTH1] Enter case"); + + if (receivedCmd_len != 8) { + cardSTATE_TO_IDLE(); + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("MFEMUL_AUTH1: receivedCmd_len != 8 (%d) => cardSTATE_TO_IDLE())", receivedCmd_len); + break; + } + + nr = bytes_to_num(receivedCmd, 4); + ar = bytes_to_num(&receivedCmd[4], 4); + + // Collect AR/NR per keytype & sector + if ((flags & FLAG_NR_AR_ATTACK) == 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; + 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 KO + if (cardRr != prng_successor(nonce, 64)) { + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[MFEMUL_AUTH1] AUTH FAILED for sector %d with key %c. [nr=%08x cardRr=%08x] [nt=%08x succ=%08x]" + , cardAUTHSC + , (cardAUTHKEY == 0) ? 'A' : 'B' + , nr + , cardRr + , nonce // nt + , prng_successor(nonce, 64) + ); + } + cardAUTHKEY = AUTHKEYNONE; // not authenticated + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + cardSTATE_TO_IDLE(); + break; + } + + ans = prng_successor(nonce, 96); + num_to_bytes(ans, 4, rAUTH_AT); + mf_crypto1_encrypt(pcs, rAUTH_AT, 4, response_par); + EmSendCmdPar(rAUTH_AT, 4, response_par); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[MFEMUL_AUTH1] AUTH COMPLETED for sector %d with key %c. time=%d", + cardAUTHSC, + cardAUTHKEY == 0 ? 'A' : 'B', + GetTickCount() - authTimer + ); + } + LED_C_ON(); + cardSTATE = MFEMUL_WORK; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_AUTH1] cardSTATE = MFEMUL_WORK"); + break; + } + + // WRITE BL2 + case MFEMUL_WRITEBL2: { + if (receivedCmd_len == MAX_MIFARE_FRAME_SIZE) { + mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); + if (CheckCrc14A(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; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WRITEBL2] cardSTATE = MFEMUL_WORK"); + break; + } + } + cardSTATE_TO_IDLE(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WRITEBL2] cardSTATE = MFEMUL_IDLE"); + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + break; + } + + // INC + 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_TO_IDLE(); + break; + } + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardINTREG = cardINTREG + ans; + + cardSTATE = MFEMUL_WORK; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_INTREG_INC] cardSTATE = MFEMUL_WORK"); + break; + } + } + + // DEC + case MFEMUL_INTREG_DEC: { + if (receivedCmd_len == 6) { // Data is encrypted + // Decrypted cmd + mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans); + 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->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardINTREG = cardINTREG - ans; + cardSTATE = MFEMUL_WORK; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_INTREG_DEC] cardSTATE = MFEMUL_WORK"); + break; + } + + // REST + 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_TO_IDLE(); + break; + } + LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + cardSTATE = MFEMUL_WORK; + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_INTREG_REST] cardSTATE = MFEMUL_WORK"); + break; + } + + } // End Switch Loop + + button_pushed = BUTTON_PRESS(); + + } // End While Loop + + + // NR AR ATTACK + if (((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) && (DBGLEVEL >= 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 < ATTACK_KEY_COUNT / 2) ? "keyA" : "keyB", ar_nr_resp[i].sector); + Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", + ar_nr_resp[i].cuid, //UID + ar_nr_resp[i].nonce, //NT + ar_nr_resp[i].nr, //NR1 + ar_nr_resp[i].ar, //AR1 + ar_nr_resp[i].nr2, //NR2 + ar_nr_resp[i].ar2 //AR2 + ); + } + } + } + + for (uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT * 2; 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 < ATTACK_KEY_COUNT / 2) ? "keyA" : "keyB", ar_nr_resp[i].sector); + Dbprintf("../tools/mfkey/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x", + ar_nr_resp[i].cuid, //UID + ar_nr_resp[i].nonce, //NT + ar_nr_resp[i].nr, //NR1 + ar_nr_resp[i].ar, //AR1 + ar_nr_resp[i].nonce2,//NT2 + ar_nr_resp[i].nr2, //NR2 + ar_nr_resp[i].ar2 //AR2 + ); + } + } + + if (DBGLEVEL >= DBG_ERROR) { + Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); + } + + + if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK + //Send the collected ar_nr in the response + reply_old(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); + BigBuf_free_keep_EM(); +} diff --git a/armsrc/mifaresim.h b/armsrc/mifaresim.h new file mode 100644 index 000000000..2dc9650cc --- /dev/null +++ b/armsrc/mifaresim.h @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// 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 + +#ifndef CheckCrc14A +# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) +#endif + +void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain); + +#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 + +#endif diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index 3e6255354..1d7f576af 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -1,324 +1,327 @@ -//----------------------------------------------------------------------------- -// 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" - -//static int sniffState = SNF_INIT; -static uint8_t sniffUIDType = 0; -static uint8_t sniffUID[10] = {0,0,0,0,0,0,0,0,0,0}; -static uint8_t sniffATQA[2] = {0,0}; -static uint8_t sniffSAK = 0; -static uint8_t sniffBuf[17]; -static uint32_t timerData = 0; - -//----------------------------------------------------------------------------- -// MIFARE sniffer. -// -// if no activity for 2sec, it sends the collected data to the client. -//----------------------------------------------------------------------------- -// "hf mf sniff" -void RAMFUNC SniffMifare(uint8_t param) { - // param: - // bit 0 - trigger from first card answer - // bit 1 - trigger from first reader 7-bit request - - // C(red) A(yellow) B(green) - LEDsoff(); - iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); BigBuf_Clear_ext(false); - clear_trace(); - set_tracing(true); - - // The command (reader -> tag) that we're receiving. - uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedCmdPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - // The response (tag -> reader) that we're receiving. - uint8_t receivedResp[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedRespPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - // allocate the DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - uint8_t *data = dmaBuf; - uint8_t previous_data = 0; - int maxDataLen = 0; - int dataLen = 0; - bool ReaderIsActive = false; - bool TagIsActive = 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 - // response from the tag. - // triggered == false -- to wait first for card - //bool triggered = !(param & 0x03); - - - // Set up the demodulator for tag -> reader responses. - DemodInit(receivedResp, receivedRespPar); - - // Set up the demodulator for the reader -> tag commands - UartInit(receivedCmd, receivedCmdPar); - - // Setup and start DMA. - // set transfer address and number of bytes. Start transfer. - if ( !FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE) ){ - if (MF_DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting"); - return; - } - - tUart* uart = GetUart(); - tDemod* demod = GetDemod(); - - MfSniffInit(); - - uint32_t sniffCounter = 0; - // loop and listen - while (!BUTTON_PRESS()) { - WDT_HIT(); - LED_A_ON(); -/* - 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 (BigBuf_get_traceLen()) { - MfSniffSend(); - // Reset everything - we missed some sniffed data anyway while the DMA was stopped - sniffCounter = 0; - dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - data = dmaBuf; - maxDataLen = 0; - ReaderIsActive = false; - TagIsActive = false; - FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. - } - } - */ - - // number of bytes we have processed so far - int register readBufDataP = data - dmaBuf; - // number of bytes already transferred - int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; - 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)) { - Dbprintf("[!] blew circular buffer! | datalen %u", dataLen); - break; - } - } - if (dataLen < 1) continue; - - // primary buffer was stopped ( <-- we lost data! - if (!AT91C_BASE_PDC_SSC->PDC_RCR) { - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t)dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; - Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary - } - // secondary buffer sets as primary, secondary buffer was stopped - if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; - } - - LED_A_OFF(); - - // Need two samples to feed Miller and Manchester-Decoder - if (sniffCounter & 0x01) { - - // no need to try decoding tag data if the reader is sending - if (!TagIsActive) { - uint8_t readerbyte = (previous_data & 0xF0) | (*data >> 4); - if (MillerDecoding(readerbyte, (sniffCounter-1)*4)) { - LogTrace(receivedCmd, uart->len, 0, 0, NULL, true); - DemodReset(); - UartReset(); - } - ReaderIsActive = (uart->state != STATE_UNSYNCD); - } - - // no need to try decoding tag data if the reader is sending - if (!ReaderIsActive) { - uint8_t tagbyte = (previous_data << 4) | (*data & 0x0F); - if (ManchesterDecoding(tagbyte, 0, (sniffCounter-1)*4)) { - LogTrace(receivedResp, demod->len, 0, 0, NULL, false); - DemodReset(); - UartReset(); - } - TagIsActive = (demod->state != DEMOD_UNSYNCD); - } - } - previous_data = *data; - sniffCounter++; - data++; - - if (data == dmaBuf + DMA_BUFFER_SIZE) - data = dmaBuf; - - } // main cycle - - MfSniffEnd(); - switch_off(); -} - -void MfSniffInit(void){ - memset(sniffUID, 0x00, sizeof(sniffUID)); - memset(sniffATQA, 0x00, sizeof(sniffATQA)); - memset(sniffBuf, 0x00, sizeof(sniffBuf)); - sniffSAK = 0; - sniffUIDType = SNF_UID_4; - timerData = 0; -} - -void MfSniffEnd(void){ - LED_B_ON(); - cmd_send(CMD_ACK,0,0,0,0,0); - LED_B_OFF(); -} - -/* -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { - - // reset on 7-Bit commands from reader - if (reader && (len == 1) && (bitCnt == 7)) { - sniffState = SNF_INIT; - } - - - - switch (sniffState) { - case SNF_INIT:{ - // REQA,WUPA or MAGICWUP from reader - if ((len == 1) && (reader) && (bitCnt == 7) ) { - MfSniffInit(); - sniffState = (data[0] == MIFARE_MAGICWUPC1) ? SNF_MAGIC_WUPC2 : SNF_ATQA; - } - break; - } - case SNF_MAGIC_WUPC2: { - if ((len == 1) && (reader) && (data[0] == MIFARE_MAGICWUPC2) ) { - sniffState = SNF_CARD_IDLE; - } - break; - } - case SNF_ATQA:{ - // ATQA from tag - if ((!reader) && (len == 2)) { - sniffATQA[0] = data[0]; - sniffATQA[1] = data[1]; - sniffState = SNF_UID; - } - break; - } - case SNF_UID: { - - if ( !reader ) break; - if ( len != 9 ) break; - if ( !CheckCrc14443(CRC_14443_A, data, 9)) break; - if ( data[1] != 0x70 ) break; - - Dbprintf("[!] UID | %x", data[0]); - - if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT)) { - // UID_4 - select 4 Byte UID from reader - memcpy(sniffUID, data+2, 4); - sniffUIDType = SNF_UID_4; - sniffState = SNF_SAK; - } else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2)) { - // UID_7 - Select 2nd part of 7 Byte UID - - // get rid of 0x88 - sniffUID[0] = sniffUID[1]; - sniffUID[1] = sniffUID[2]; - sniffUID[2] = sniffUID[3]; - //new uid bytes - memcpy(sniffUID+3, data+2, 4); - sniffUIDType = SNF_UID_7; - sniffState = SNF_SAK; - } else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3)) { - // UID_10 - Select 3nd part of 10 Byte UID - // 3+3+4 = 10. - // get ride of previous 0x88 - sniffUID[3] = sniffUID[4]; - sniffUID[4] = sniffUID[5]; - sniffUID[5] = sniffUID[6]; - // new uid bytes - memcpy(sniffUID+6, data+2, 4); - sniffUIDType = SNF_UID_10; - sniffState = SNF_SAK; - } - break; - } - case SNF_SAK:{ - // SAK from card? - if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { - sniffSAK = data[0]; - // CL2 UID part to be expected - if (( sniffSAK == 0x04) && (sniffUIDType == SNF_UID_4)) { - sniffState = SNF_UID; - // CL3 UID part to be expected - } else if ((sniffSAK == 0x04) && (sniffUIDType == SNF_UID_7)) { - sniffState = SNF_UID; - } else { - // select completed - sniffState = SNF_CARD_IDLE; - } - } - break; - } - case SNF_CARD_IDLE:{ // trace the card select sequence - sniffBuf[0] = 0xFF; - sniffBuf[1] = 0xFF; - memcpy(sniffBuf + 2, sniffUID, sizeof(sniffUID)); - memcpy(sniffBuf + 12, sniffATQA, sizeof(sniffATQA)); - sniffBuf[14] = sniffSAK; - sniffBuf[15] = 0xFF; - sniffBuf[16] = 0xFF; - LogTrace(sniffBuf, sizeof(sniffBuf), 0, 0, NULL, true); - sniffState = SNF_CARD_CMD; - } // intentionally no break; - case SNF_CARD_CMD:{ - LogTrace(data, len, 0, 0, NULL, reader); - timerData = GetTickCount(); - break; - } - default: - sniffState = SNF_INIT; - break; - } - return false; -} -*/ - -void RAMFUNC MfSniffSend() { - uint16_t tracelen = BigBuf_get_traceLen(); - uint16_t chunksize = 0; - int packlen = tracelen; // total number of bytes to send - uint8_t *data = BigBuf_get_addr(); - - while (packlen > 0) { - LED_B_ON(); - chunksize = MIN(USB_CMD_DATA_SIZE, packlen); // chunk size 512 - cmd_send(CMD_ACK, 1, tracelen, chunksize, data + tracelen - packlen, chunksize); - packlen -= chunksize; - LED_B_OFF(); - } - - LED_B_ON(); - cmd_send(CMD_ACK, 2, 0, 0, 0, 0); // 2 == data transfer finished. - LED_B_OFF(); -} \ No newline at end of file +//----------------------------------------------------------------------------- +// 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" + +#ifndef CheckCrc14A +# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) +#endif + +//static int sniffState = SNF_INIT; +static uint8_t sniffUIDType = 0; +static uint8_t sniffUID[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static uint8_t sniffATQA[2] = {0, 0}; +static uint8_t sniffSAK = 0; +static uint8_t sniffBuf[17]; +static uint32_t timerData = 0; + +//----------------------------------------------------------------------------- +// MIFARE sniffer. +// +// if no activity for 2sec, it sends the collected data to the client. +//----------------------------------------------------------------------------- +// "hf mf sniff" +void RAMFUNC SniffMifare(uint8_t param) { + // param: + // bit 0 - trigger from first card answer + // bit 1 - trigger from first reader 7-bit request + + // C(red) A(yellow) B(green) + LEDsoff(); + iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); + + // Allocate memory from BigBuf for some buffers + // free all previous allocations first + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + // The command (reader -> tag) that we're receiving. + uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedCmdPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + // The response (tag -> reader) that we're receiving. + uint8_t receivedResp[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedRespPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + // allocate the DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + uint8_t *data = dmaBuf; + uint8_t previous_data = 0; + int dataLen, maxDataLen = 0; + bool ReaderIsActive = false; + bool TagIsActive = 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 + // response from the tag. + // triggered == false -- to wait first for card + //bool triggered = !(param & 0x03); + + + // Set up the demodulator for tag -> reader responses. + DemodInit(receivedResp, receivedRespPar); + + // Set up the demodulator for the reader -> tag commands + UartInit(receivedCmd, receivedCmdPar); + + // Setup and start DMA. + // set transfer address and number of bytes. Start transfer. + if (!FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE)) { + if (DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting"); + return; + } + + tUart *uart = GetUart(); + tDemod *demod = GetDemod(); + + MfSniffInit(); + + uint32_t sniffCounter = 0; + // loop and listen + while (!BUTTON_PRESS()) { + WDT_HIT(); + LED_A_ON(); + /* + 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 (BigBuf_get_traceLen()) { + MfSniffSend(); + // Reset everything - we missed some sniffed data anyway while the DMA was stopped + sniffCounter = 0; + dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + data = dmaBuf; + maxDataLen = 0; + ReaderIsActive = false; + TagIsActive = false; + FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. + } + } + */ + + // number of bytes we have processed so far + int register readBufDataP = data - dmaBuf; + // number of bytes already transferred + int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; + 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)) { + Dbprintf("[!] blew circular buffer! | datalen %u", dataLen); + break; + } + } + if (dataLen < 1) continue; + + // primary buffer was stopped ( <-- we lost data! + if (!AT91C_BASE_PDC_SSC->PDC_RCR) { + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t)dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE; + Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary + } + // secondary buffer sets as primary, secondary buffer was stopped + if (!AT91C_BASE_PDC_SSC->PDC_RNCR) { + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)dmaBuf; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } + + LED_A_OFF(); + + // Need two samples to feed Miller and Manchester-Decoder + if (sniffCounter & 0x01) { + + // no need to try decoding tag data if the reader is sending + if (!TagIsActive) { + uint8_t readerbyte = (previous_data & 0xF0) | (*data >> 4); + if (MillerDecoding(readerbyte, (sniffCounter - 1) * 4)) { + LogTrace(receivedCmd, uart->len, 0, 0, NULL, true); + DemodReset(); + UartReset(); + } + ReaderIsActive = (uart->state != STATE_UNSYNCD); + } + + // no need to try decoding tag data if the reader is sending + if (!ReaderIsActive) { + uint8_t tagbyte = (previous_data << 4) | (*data & 0x0F); + if (ManchesterDecoding(tagbyte, 0, (sniffCounter - 1) * 4)) { + LogTrace(receivedResp, demod->len, 0, 0, NULL, false); + DemodReset(); + UartReset(); + } + TagIsActive = (demod->state != DEMOD_UNSYNCD); + } + } + previous_data = *data; + sniffCounter++; + data++; + + if (data == dmaBuf + DMA_BUFFER_SIZE) + data = dmaBuf; + + } // main cycle + + MfSniffEnd(); + switch_off(); +} + +void MfSniffInit(void) { + memset(sniffUID, 0x00, sizeof(sniffUID)); + memset(sniffATQA, 0x00, sizeof(sniffATQA)); + memset(sniffBuf, 0x00, sizeof(sniffBuf)); + sniffSAK = 0; + sniffUIDType = SNF_UID_4; + timerData = 0; +} + +void MfSniffEnd(void) { + LED_B_ON(); + reply_old(CMD_ACK, 0, 0, 0, 0, 0); + LED_B_OFF(); +} + +/* +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { + + // reset on 7-Bit commands from reader + if (reader && (len == 1) && (bitCnt == 7)) { + sniffState = SNF_INIT; + } + + + + switch (sniffState) { + case SNF_INIT:{ + // REQA,WUPA or MAGICWUP from reader + if ((len == 1) && (reader) && (bitCnt == 7) ) { + MfSniffInit(); + sniffState = (data[0] == MIFARE_MAGICWUPC1) ? SNF_MAGIC_WUPC2 : SNF_ATQA; + } + break; + } + case SNF_MAGIC_WUPC2: { + if ((len == 1) && (reader) && (data[0] == MIFARE_MAGICWUPC2) ) { + sniffState = SNF_CARD_IDLE; + } + break; + } + case SNF_ATQA:{ + // ATQA from tag + if ((!reader) && (len == 2)) { + sniffATQA[0] = data[0]; + sniffATQA[1] = data[1]; + sniffState = SNF_UID; + } + break; + } + case SNF_UID: { + + if ( !reader ) break; + if ( len != 9 ) break; + if ( !CheckCrc14A(data, 9)) break; + if ( data[1] != 0x70 ) break; + + Dbprintf("[!] UID | %x", data[0]); + + if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT)) { + // UID_4 - select 4 Byte UID from reader + memcpy(sniffUID, data+2, 4); + sniffUIDType = SNF_UID_4; + sniffState = SNF_SAK; + } else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2)) { + // UID_7 - Select 2nd part of 7 Byte UID + + // get rid of 0x88 + sniffUID[0] = sniffUID[1]; + sniffUID[1] = sniffUID[2]; + sniffUID[2] = sniffUID[3]; + //new uid bytes + memcpy(sniffUID+3, data+2, 4); + sniffUIDType = SNF_UID_7; + sniffState = SNF_SAK; + } else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3)) { + // UID_10 - Select 3nd part of 10 Byte UID + // 3+3+4 = 10. + // get ride of previous 0x88 + sniffUID[3] = sniffUID[4]; + sniffUID[4] = sniffUID[5]; + sniffUID[5] = sniffUID[6]; + // new uid bytes + memcpy(sniffUID+6, data+2, 4); + sniffUIDType = SNF_UID_10; + sniffState = SNF_SAK; + } + break; + } + case SNF_SAK:{ + // SAK from card? + if ((!reader) && (len == 3) && (CheckCrc14A(data, 3))) { + sniffSAK = data[0]; + // CL2 UID part to be expected + if (( sniffSAK == 0x04) && (sniffUIDType == SNF_UID_4)) { + sniffState = SNF_UID; + // CL3 UID part to be expected + } else if ((sniffSAK == 0x04) && (sniffUIDType == SNF_UID_7)) { + sniffState = SNF_UID; + } else { + // select completed + sniffState = SNF_CARD_IDLE; + } + } + break; + } + case SNF_CARD_IDLE:{ // trace the card select sequence + sniffBuf[0] = 0xFF; + sniffBuf[1] = 0xFF; + memcpy(sniffBuf + 2, sniffUID, sizeof(sniffUID)); + memcpy(sniffBuf + 12, sniffATQA, sizeof(sniffATQA)); + sniffBuf[14] = sniffSAK; + sniffBuf[15] = 0xFF; + sniffBuf[16] = 0xFF; + LogTrace(sniffBuf, sizeof(sniffBuf), 0, 0, NULL, true); + sniffState = SNF_CARD_CMD; + } // intentionally no break; + case SNF_CARD_CMD:{ + LogTrace(data, len, 0, 0, NULL, reader); + timerData = GetTickCount(); + break; + } + default: + sniffState = SNF_INIT; + break; + } + return false; +} +*/ + +void RAMFUNC MfSniffSend() { + uint16_t tracelen = BigBuf_get_traceLen(); + int packlen = tracelen; // total number of bytes to send + uint8_t *data = BigBuf_get_addr(); + + while (packlen > 0) { + LED_B_ON(); + uint16_t chunksize = MIN(PM3_CMD_DATA_SIZE, packlen); // chunk size 512 + reply_old(CMD_ACK, 1, tracelen, chunksize, data + tracelen - packlen, chunksize); + packlen -= chunksize; + LED_B_OFF(); + } + + LED_B_ON(); + reply_old(CMD_ACK, 2, 0, 0, 0, 0); // 2 == data transfer finished. + LED_B_OFF(); +} diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index 537fa2941..198d14daf 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -1,42 +1,41 @@ -//----------------------------------------------------------------------------- -// Merlok - June 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. -//----------------------------------------------------------------------------- - -#ifndef __MIFARESNIFF_H -#define __MIFARESNIFF_H - -#include "proxmark3.h" -#include "apps.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" - -#define SNF_INIT 0 -#define SNF_NO_FIELD 1 -#define SNF_ATQA 2 -#define SNF_UID 3 -#define SNF_SAK 4 -#define SNF_CARD_IDLE 5 -#define SNF_CARD_CMD 6 -#define SNF_MAGIC_WUPC2 7 - -#define SNF_UID_4 0 -#define SNF_UID_7 0 -#define SNF_UID_10 0 - -void MfSniffInit(void); -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader); -void RAMFUNC MfSniffSend(void); -void MfSniffEnd(void); - -#endif \ No newline at end of file +//----------------------------------------------------------------------------- +// Merlok - June 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. +//----------------------------------------------------------------------------- + +#ifndef __MIFARESNIFF_H +#define __MIFARESNIFF_H + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" +#include "iso14443a.h" +#include "crapto1/crapto1.h" +#include "mifareutil.h" +#include "common.h" + +#define SNF_INIT 0 +#define SNF_NO_FIELD 1 +#define SNF_ATQA 2 +#define SNF_UID 3 +#define SNF_SAK 4 +#define SNF_CARD_IDLE 5 +#define SNF_CARD_CMD 6 +#define SNF_MAGIC_WUPC2 7 + +#define SNF_UID_4 0 +#define SNF_UID_7 0 +#define SNF_UID_10 0 + +void MfSniffInit(void); +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader); +void RAMFUNC MfSniffSend(void); +void MfSniffEnd(void); + +#endif diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 179b9c51e..6142198a5 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -1,689 +1,702 @@ -//----------------------------------------------------------------------------- -// Merlok, May 2011, 2012 -// Many authors, whom made it possible -// -// 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. -//----------------------------------------------------------------------------- -// Work with mifare cards. -//----------------------------------------------------------------------------- -#include "mifareutil.h" - -int MF_DBGLEVEL = MF_DBG_ERROR; - -// crypto1 helpers -void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){ - 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]; - } else { - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 0)) << 0; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 1)) << 1; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 2)) << 2; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 3)) << 3; - data_out[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_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { - uint8_t bt = 0; - int i; - par[0] = 0; - - for (i = 0; i < len; i++) { - bt = data[i]; - data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; - if ( ( i & 0x0007 ) == 0) - par[ i >> 3 ] = 0; - par[ i >> 3 ] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); - } -} - -uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { - uint8_t bt = 0; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 0)) << 0; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 1)) << 1; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 2)) << 2; - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 3)) << 3; - 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); - AddCrc14A(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 len; -} - -// 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) { - uint16_t pos, res; - uint8_t dcmd[4] = {cmd, data, 0x00, 0x00}; - uint8_t ecmd[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t par[1] = {0x00}; // 1 Byte parity is enough here - AddCrc14A(dcmd, 2); - memcpy(ecmd, dcmd, sizeof(dcmd)); - - if (crypted) { - par[0] = 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)); - } - ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); - } else { - ReaderTransmit(dcmd, sizeof(dcmd), timing); - } - - int len = ReaderReceive(answer, par); - - if (answer_parity) *answer_parity = par[0]; - - if (crypted == CRYPT_ALL) { - if (len == 1) { - res = 0; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 0)) << 0; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 1)) << 1; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 2)) << 2; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 3)) << 3; - answer[0] = res; - } else { - for (pos = 0; pos < len; pos++) - answer[pos] = crypto1_byte(pcs, 0x00, 0) ^ answer[pos]; - } - } - 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) { - 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) { - int len; - uint32_t pos, nt, ntpp; // Supplied tag nonce - uint8_t par[1] = {0x00}; - uint8_t nr[4]; - uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - // "random" reader nonce: - num_to_bytes( prng_successor( GetTickCount(), 32), 4, nr); - - // Transmit MIFARE_CLASSIC_AUTH - len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); - if (len != 4) return 1; - - // Save the tag nonce (nt) - nt = bytes_to_num(receivedAnswer, 4); - - // ----------------------------- crypto1 create - if (isNested) - crypto1_destroy(pcs); - - // Init cipher with key - crypto1_create(pcs, ui64Key); - - if (isNested == AUTH_NESTED) { - // decrypt nt with help of new key - nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; - } else { - // Load (plain) uid^nt into the cipher - crypto1_word(pcs, nt ^ uid, 0); - } - - // some statistic - if (!ntptr && (MF_DBGLEVEL >= MF_DBG_EXTENDED)) - Dbprintf("auth uid: %08x | nr: %08x | nt: %08x", uid, nr, nt); - - // save Nt - if (ntptr) - *ntptr = nt; - - // 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)); - } - - // Skip 32 bits in pseudo random generator - nt = prng_successor(nt, 32); - - // ar+parity - 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 & 0xff)) & 0x01) << (7-pos)); - } - - // Transmit reader nonce and reader answer - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); - - // Receive 4 byte tag answer - len = ReaderReceive(receivedAnswer, receivedAnswerPar); - if (!len) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout."); - return 2; - } - - ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); - - if (ntpp != bytes_to_num(receivedAnswer, 4)) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) 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 len; - uint8_t bt[2] = {0x00, 0x00}; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if (len == 1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - if (len != 18) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: wrong response len: %x (expected 18)", len); - return 2; - } - - memcpy(bt, receivedAnswer + 16, 2); - AddCrc14A(receivedAnswer, 16); - if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= MF_DBG_ALL) 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 = 0; - uint8_t resp[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t respPar[1] = {0x00}; - uint8_t key[4] = {0x00, 0x00, 0x00, 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); - - 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 - 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 = 0; - 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((void*)random_b, (void*)enc_random_b, sizeof(random_b), (const void*)key, IV ); - 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); - - 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); - 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; -} - -int mifare_ultra_readblockEx(uint8_t blockNo, uint8_t *blockData) { - uint16_t len = 0; - uint8_t bt[2] = {0x00, 0x00}; - uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; - - len = mifare_sendcmd_short(NULL, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if (len == 1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - if (len != 18) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len); - return 2; - } - - memcpy(bt, receivedAnswer + 16, 2); - AddCrc14A(receivedAnswer, 16); - if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd CRC response error."); - return 3; - } - - memcpy(blockData, receivedAnswer, 14); - return 0; -} -int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) { - #define MFU_MAX_RETRIES 5 - uint8_t res; - - for (uint8_t retries = 0; retries < MFU_MAX_RETRIES; ++retries) { - res = mifare_ultra_readblockEx(blockNo, blockData); - - // break if OK, or NACK. - switch ( res ) { - case 0: - case 1: - return res; - default: - continue; - } - } - return res; -} - -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { - // variables - uint16_t len = 0; - uint32_t pos = 0; - uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send - byte_t res = 0; - - uint8_t d_block[18], d_block_enc[18]; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - - memcpy(d_block, blockData, 16); - AddCrc14A(d_block, 16); - - // crypto - 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))); - } - - ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); - - // Receive the response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); - - res = 0; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2; - res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; - - if ((len != 1) || (res != 0x0A)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); - return 2; - } - 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, ISO14443A_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); - AddCrc14A(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 = 0; - uint8_t block[5] = {blockNo, 0x00, 0x00, 0x00, 0x00 }; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; - - // command MIFARE_CLASSIC_WRITEBLOCK - memcpy(block+1, blockData, 4); - - len = mifare_sendcmd( MIFARE_ULC_WRITE, block, sizeof(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_ex(struct Crypto1State *pcs) { - uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; - uint16_t len = mifare_sendcmd_short(pcs, (pcs == NULL) ? CRYPT_NONE : CRYPT_ALL, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL); - if (len != 0) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("halt warning. response len: %x", len); - return 1; - } - return 0; -} -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { - return mifare_classic_halt_ex(pcs); -} - -int mifare_ultra_halt() { - uint16_t len = 0; - uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; - len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL); - if (len != 0) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("halt warning. 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) { - return (sectorNo < 32) ? 4 : 16; -} - -uint8_t FirstBlockOfSector(uint8_t sectorNo) { - if (sectorNo < 32) - return sectorNo * 4; - else - return 32*4 + (sectorNo - 32) * 16; - -} - -// work with emulator memory -void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { - emlSetMem_xt(data, blockNum, blocksCount, 16); -} - -void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) { - uint8_t* emCARD = BigBuf_get_EM_addr(); - memcpy(emCARD + blockNum * blockBtWidth, data, blocksCount * blockBtWidth); -} - -void emlGetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = BigBuf_get_EM_addr(); - memcpy(data, emCARD + blockNum * 16, blocksCount * 16); -} - -void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount) { - uint8_t* emCARD = BigBuf_get_EM_addr(); - memcpy(data, emCARD + bytePtr, byteCount); -} - -int emlCheckValBl(int blockNum) { - uint8_t* emCARD = BigBuf_get_EM_addr(); - uint8_t* data = emCARD + blockNum * 16; - - if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) || - (data[1] != (data[5] ^ 0xff)) || (data[1] != data[9]) || - (data[2] != (data[6] ^ 0xff)) || (data[2] != data[10]) || - (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* 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* 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] = {0x00}; - uint8_t* emCARD = BigBuf_get_EM_addr(); - memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); - return bytes_to_num(key, 6); -} - -void emlClearMem(void) { - 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); - - // fill sectors trailer data - for(uint16_t 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] = {cmd, data[0], data[1], 0x00, 0x00}; - AddCrc14A(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); - AddCrc14A(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]={MFDES_AUTHENTICATE, 0x00}; - uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; - - 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] = {MFDES_AUTHENTICATION_FRAME}; - memcpy(data+1,key,16); - - uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; - - 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; -} +// Merlok, May 2011, 2012 +// Many authors, whom made it possible +// +// 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. +//----------------------------------------------------------------------------- +// Work with mifare cards. +//----------------------------------------------------------------------------- +#include "mifareutil.h" + +int DBGLEVEL = DBG_ERROR; + +// crypto1 helpers +void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out) { + if (len != 1) { + for (int i = 0; i < len; i++) + data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i]; + } else { + uint8_t bt = 0; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 0)) << 0; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 1)) << 1; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 2)) << 2; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], 3)) << 3; + data_out[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_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { + mf_crypto1_encryptEx(pcs, data, NULL, data, len, par); +} + +void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data_in, uint8_t *keystream, uint8_t *data_out, uint16_t len, uint8_t *par) { + int i; + par[0] = 0; + + for (i = 0; i < len; i++) { + uint8_t bt = data_in[i]; + data_out[i] = crypto1_byte(pcs, keystream ? keystream[i] : 0x00, 0) ^ data_in[i]; + if ((i & 0x0007) == 0) + par[ i >> 3 ] = 0; + par[ i >> 3 ] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01) << (7 - (i & 0x0007))); + } +} + +uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { + uint8_t bt = 0; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 0)) << 0; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 1)) << 1; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 2)) << 2; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, 3)) << 3; + 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); + AddCrc14A(dcmd, data_size + 1); + ReaderTransmit(dcmd, sizeof(dcmd), timing); + int len = ReaderReceive(answer, answer_parity); + if (!len) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("%02X Cmd failed. Card timeout.", cmd); + len = ReaderReceive(answer, answer_parity); + } + return len; +} + +// 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) { + uint16_t pos; + uint8_t dcmd[4] = {cmd, data, 0x00, 0x00}; + uint8_t ecmd[4] = {0x00, 0x00, 0x00, 0x00}; + uint8_t par[1] = {0x00}; // 1 Byte parity is enough here + AddCrc14A(dcmd, 2); + memcpy(ecmd, dcmd, sizeof(dcmd)); + + if (crypted) { + par[0] = 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)); + } + ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); + } else { + ReaderTransmit(dcmd, sizeof(dcmd), timing); + } + + int len = ReaderReceive(answer, par); + + if (answer_parity) *answer_parity = par[0]; + + if (crypted == CRYPT_ALL) { + if (len == 1) { + uint16_t res = 0; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 0)) << 0; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 1)) << 1; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 2)) << 2; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 3)) << 3; + answer[0] = res; + } else { + for (pos = 0; pos < len; pos++) + answer[pos] = crypto1_byte(pcs, 0x00, 0) ^ answer[pos]; + } + } + 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) { + 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) { + int len; + uint32_t pos, nt, ntpp; // Supplied tag nonce + uint8_t par[1] = {0x00}; + uint8_t nr[4]; + uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + // "random" reader nonce: + num_to_bytes(prng_successor(GetTickCount(), 32), 4, nr); + + // Transmit MIFARE_CLASSIC_AUTH + len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); + if (len != 4) return 1; + + // Save the tag nonce (nt) + nt = bytes_to_num(receivedAnswer, 4); + + // ----------------------------- crypto1 create + if (isNested) + crypto1_destroy(pcs); + + // Init cipher with key + crypto1_create(pcs, ui64Key); + + if (isNested == AUTH_NESTED) { + // decrypt nt with help of new key + nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; + } else { + // Load (plain) uid^nt into the cipher + crypto1_word(pcs, nt ^ uid, 0); + } + + // some statistic + if (!ntptr && (DBGLEVEL >= DBG_EXTENDED)) + Dbprintf("auth uid: %08x | nr: %08x | nt: %08x", uid, nr, nt); + + // save Nt + if (ntptr) + *ntptr = nt; + + // 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)); + } + + // Skip 32 bits in pseudo random generator + nt = prng_successor(nt, 32); + + // ar+parity + 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 & 0xff)) & 0x01) << (7 - pos)); + } + + // Transmit reader nonce and reader answer + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); + + // Receive 4 byte tag answer + len = ReaderReceive(receivedAnswer, receivedAnswerPar); + if (!len) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout."); + return 2; + } + + ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0); + + if (ntpp != bytes_to_num(receivedAnswer, 4)) { + if (DBGLEVEL >= DBG_EXTENDED) 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 len; + uint8_t bt[2] = {0x00, 0x00}; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + if (len == 1) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len != 18) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: wrong response len: %x (expected 18)", len); + return 2; + } + + memcpy(bt, receivedAnswer + 16, 2); + AddCrc14A(receivedAnswer, 16); + if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { + if (DBGLEVEL >= DBG_INFO) 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 = 0; + uint8_t resp[4] = {0x00, 0x00, 0x00, 0x00}; + uint8_t respPar[1] = {0x00}; + uint8_t key[4] = {0x00, 0x00, 0x00, 0x00}; + memcpy(key, keybytes, 4); + + if (DBGLEVEL >= 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); + + if (len != 4) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len); + return 0; + } + + if (DBGLEVEL >= 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 + 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 = 0; + 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 (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); + return 0; + } + + // tag nonce. + memcpy(enc_random_b, resp + 1, 8); + + // decrypt nonce. + tdes_2key_dec((void *)random_b, (void *)enc_random_b, sizeof(random_b), (const void *)key, IV); + rol(random_b, 8); + memcpy(rnd_ab, random_a, 8); + memcpy(rnd_ab + 8, random_b, 8); + + if (DBGLEVEL >= 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); + + len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); + if (len != 11) { + if (DBGLEVEL >= 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); + if (memcmp(resp_random_a, random_a, 8) != 0) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("failed authentication"); + return 0; + } + + if (DBGLEVEL >= 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; +} + +int mifare_ultra_readblockEx(uint8_t blockNo, uint8_t *blockData) { + uint16_t len = 0; + uint8_t bt[2] = {0x00, 0x00}; + uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; + + len = mifare_sendcmd_short(NULL, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + if (len == 1) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len != 18) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len); + return 2; + } + + memcpy(bt, receivedAnswer + 16, 2); + AddCrc14A(receivedAnswer, 16); + if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd CRC response error."); + return 3; + } + + memcpy(blockData, receivedAnswer, 16); + return 0; +} +int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) { +#define MFU_MAX_RETRIES 5 + uint8_t res; + + for (uint8_t retries = 0; retries < MFU_MAX_RETRIES; ++retries) { + res = mifare_ultra_readblockEx(blockNo, blockData); + + // break if OK, or NACK. + switch (res) { + case 0: + case 1: + return res; + default: + continue; + } + } + return res; +} + +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { + // variables + uint16_t len = 0; + uint32_t pos = 0; + uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send + uint8_t res = 0; + + uint8_t d_block[18], d_block_enc[18]; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + // command MIFARE_CLASSIC_WRITEBLOCK + len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + + memcpy(d_block, blockData, 16); + AddCrc14A(d_block, 16); + + // crypto + 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))); + } + + ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); + + // Receive the response + len = ReaderReceive(receivedAnswer, receivedAnswerPar); + + res = 0; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2; + res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; + + if ((len != 1) || (res != 0x0A)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); + return 2; + } + 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, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (DBGLEVEL >= DBG_ERROR) + Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); + return 1; + } + + memcpy(d_block, blockData, 16); + AddCrc14A(d_block, 16); + + ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); + + len = ReaderReceive(receivedAnswer, receivedAnswerPar); + + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (DBGLEVEL >= 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 = 0; + uint8_t block[5] = {blockNo, 0x00, 0x00, 0x00, 0x00 }; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; + + // command MIFARE_CLASSIC_WRITEBLOCK + memcpy(block + 1, blockData, 4); + + len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL); + + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK + if (DBGLEVEL >= DBG_ERROR) + Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); + return 1; + } + return 0; +} +int mifare_classic_halt_ex(struct Crypto1State *pcs) { + uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; + uint16_t len = mifare_sendcmd_short(pcs, (pcs == NULL) ? CRYPT_NONE : CRYPT_ALL, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL); + if (len != 0) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("halt warning. response len: %x", len); + return 1; + } + return 0; +} +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { + return mifare_classic_halt_ex(pcs); +} + +int mifare_ultra_halt() { + uint16_t len = 0; + uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; + len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL); + if (len != 0) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("halt warning. 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) { + return (sectorNo < 32) ? 4 : 16; +} + +uint8_t FirstBlockOfSector(uint8_t sectorNo) { + if (sectorNo < 32) + return sectorNo * 4; + else + return 32 * 4 + (sectorNo - 32) * 16; + +} + +// work with emulator memory +void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { + emlSetMem_xt(data, blockNum, blocksCount, 16); +} + +void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) { + uint8_t *emCARD = BigBuf_get_EM_addr(); + memcpy(emCARD + blockNum * blockBtWidth, data, blocksCount * blockBtWidth); +} + +void emlGetMem(uint8_t *data, int blockNum, int blocksCount) { + uint8_t *emCARD = BigBuf_get_EM_addr(); + memcpy(data, emCARD + blockNum * 16, blocksCount * 16); +} + +void emlGetMemBt(uint8_t *data, int offset, int byteCount) { + uint8_t *emCARD = BigBuf_get_EM_addr(); + memcpy(data, emCARD + offset, byteCount); +} + +int emlCheckValBl(int blockNum) { + uint8_t *emCARD = BigBuf_get_EM_addr(); + uint8_t *data = emCARD + blockNum * 16; + + if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) || + (data[1] != (data[5] ^ 0xff)) || (data[1] != data[9]) || + (data[2] != (data[6] ^ 0xff)) || (data[2] != data[10]) || + (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 *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 *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] = {0x00}; + uint8_t *emCARD = BigBuf_get_EM_addr(); + memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); + return bytes_to_num(key, 6); +} + +void emlClearMem(void) { + 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); + + // fill sectors trailer data + for (uint16_t b = 3; b <= MIFARE_4K_MAXBLOCK; ((b <= MIFARE_2K_MAXBLOCK) ? (b += 4) : (b += 16))) + emlSetMem((uint8_t *)trailer, b, 1); + + // uid + emlSetMem((uint8_t *)uid, 0, 1); + return; +} + +uint8_t SectorTrailer(uint8_t blockNo) { + if (blockNo <= MIFARE_2K_MAXBLOCK) { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Sector Trailer for block %d : %d", blockNo, (blockNo | 0x03)); + return (blockNo | 0x03); + } else { + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Sector Trailer for block %d : %d", blockNo, (blockNo | 0x0f)); + return (blockNo | 0x0f); + } +} + +bool IsSectorTrailer(uint8_t blockNo) { + return (blockNo == SectorTrailer(blockNo)); +} + +// 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] = {cmd, data[0], data[1], 0x00, 0x00}; + AddCrc14A(dcmd, 3); + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer, answer_parity); + if (!len) { + if (DBGLEVEL >= 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); + AddCrc14A(dcmd, 18); + + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer, answer_parity); + if (!len) { + if (DBGLEVEL >= 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] = {MFDES_AUTHENTICATE, 0x00}; + uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; + + len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL); + if (len == 1) { + if (DBGLEVEL >= DBG_ERROR) + Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + + if (len == 12) { + if (DBGLEVEL >= 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] = {MFDES_AUTHENTICATION_FRAME}; + memcpy(data + 1, key, 16); + + uint8_t receivedAnswer[MAX_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_PARITY_SIZE] = {0x00}; + + len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL); + + if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { + if (DBGLEVEL >= DBG_ERROR) + Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); + return 1; + } + + if (len == 12) { + if (DBGLEVEL >= 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; +} diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 268149f60..a2086c5e7 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -1,106 +1,116 @@ -//----------------------------------------------------------------------------- -// Merlok, May 2011 -// Many authors, that makes it possible -// -// 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. -//----------------------------------------------------------------------------- -// code for work with mifare cards. -//----------------------------------------------------------------------------- - -#ifndef __MIFAREUTIL_H -#define __MIFAREUTIL_H - -#include "proxmark3.h" -#include "apps.h" -#include "parity.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "des.h" -#include "random.h" // fast_prand, prand - -// mifare authentication -#define CRYPT_NONE 0 -#define CRYPT_ALL 1 -#define CRYPT_REQUEST 2 -#define AUTH_FIRST 0 -#define AUTH_NESTED 2 - -#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) -#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication - -// 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 - - - -//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 cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); - -//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); +//----------------------------------------------------------------------------- +// Merlok, May 2011 +// Many authors, that makes it possible +// +// 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. +//----------------------------------------------------------------------------- +// code for work with mifare cards. +//----------------------------------------------------------------------------- -// mifare classic -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested); -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); -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_halt_ex(struct Crypto1State *pcs); -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); - -// 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); +#ifndef __MIFAREUTIL_H +#define __MIFAREUTIL_H + +#include "proxmark3.h" +#include "apps.h" +#include "parity.h" +#include "util.h" +#include "string.h" +#include "iso14443a.h" +#include "crapto1/crapto1.h" +#include "des.h" + +// mifare authentication +#define CRYPT_NONE 0 +#define CRYPT_ALL 1 +#define CRYPT_REQUEST 2 +#define AUTH_FIRST 0 +#define AUTH_NESTED 2 + +#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) +#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication + +// reader voltage field detector +#define MF_MINFIELDV 4000 + +// Mifare 4k/2k/1k/mini Max Block / Max Sector +#define MIFARE_4K_MAXBLOCK 256 +#define MIFARE_2K_MAXBLOCK 128 +#define MIFARE_1K_MAXBLOCK 64 +#define MIFARE_MINI_MAXBLOCK 20 + +#define MIFARE_MINI_MAXSECTOR 5 +#define MIFARE_1K_MAXSECTOR 16 +#define MIFARE_2K_MAXSECTOR 32 +#define MIFARE_4K_MAXSECTOR 40 + +//mifare emulator states +#define MFEMUL_NOFIELD 0 +#define MFEMUL_IDLE 1 +#define MFEMUL_SELECT 2 +#define MFEMUL_AUTH1 3 +#define MFEMUL_WORK 4 +#define MFEMUL_WRITEBL2 5 +#define MFEMUL_INTREG_INC 6 +#define MFEMUL_INTREG_DEC 7 +#define MFEMUL_INTREG_REST 8 +#define MFEMUL_HALTED 9 + +#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); + +#ifndef MifareBlockToSector +#define MifareBlockToSector(block) (block < 128 ? block / 4 : (block - 128) / 16 + 32) +#endif + +//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 classic +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested); +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); +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_halt_ex(struct Crypto1State *pcs); +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); + +// Ultralight/NTAG... +int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack); +int mifare_ultra_auth(uint8_t *keybytes); +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); + +// 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); -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); - -// emulator functions -void emlClearMem(void); -void emlSetMem(uint8_t *data, int blockNum, int blocksCount); -void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); -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); +void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, 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_in, uint8_t *keystream, uint8_t *data_out, uint16_t len, uint8_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); + +// emulator functions +void emlClearMem(void); +void emlSetMem(uint8_t *data, int blockNum, int blocksCount); +void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); +void emlGetMem(uint8_t *data, int blockNum, int blocksCount); +void emlGetMemBt(uint8_t *data, int offset, 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); diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index 36b25f593..4894bf6bc 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -1,13 +1,13 @@ /***************************************************************************** * 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 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. * ***************************************************************************** * @@ -22,7 +22,7 @@ * * 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. + * 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 @@ -31,9 +31,9 @@ * * You should have received a copy of the GNU General Public License * along with loclass. If not, see . - * - * - * + * + * + * ****************************************************************************/ /** @@ -41,8 +41,8 @@ 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 + 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. @@ -67,162 +67,159 @@ #define opt_B(s) (((s->b >> 6) ^ (s->b >> 5) ^ (s->b >> 4) ^ (s->b)) & 0x1) #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)) + |(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) { - uint8_t r_ls2 = r << 2; - uint8_t r_and_ls2 = r & r_ls2; - uint8_t r_or_ls2 = r | r_ls2; + uint8_t r_ls2 = r << 2; + uint8_t r_and_ls2 = r & r_ls2; + uint8_t r_or_ls2 = r | r_ls2; - //r: r0 r1 r2 r3 r4 r5 r6 r7 - //r_ls2: r2 r3 r4 r5 r6 r7 0 0 - // z0 - // z1 + //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 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 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; +// 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); + return (z0 & 4) | (z1 & 2) | (z2 & 1); } */ -void opt_successor(const uint8_t* k, State *s, bool y, State* successor) { - uint8_t Tt = 1 & opt_T(s); +void opt_successor(const uint8_t *k, State *s, bool y, State *successor) { + uint8_t Tt = 1 & opt_T(s); - successor->t = (s->t >> 1); - successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15; + successor->t = (s->t >> 1); + successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15; - successor->b = s->b >> 1; - successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7; + successor->b = s->b >> 1; + successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7; - successor->r = (k[opt__select(Tt,y,s->r)] ^ successor->b) + s->l ; - successor->l = successor->r+s->r; + successor->r = (k[opt__select(Tt, y, s->r)] ^ successor->b) + s->l ; + successor->l = successor->r + s->r; } -void opt_suc(const uint8_t* k,State* s, uint8_t *in, uint8_t length, bool add32Zeroes) { - State x2; - int i; - uint8_t head = 0; - for (i = 0; i < length; i++) { - head = 1 & (in[i] >> 7); - opt_successor(k, s, head, &x2); +void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) { + State x2; + for (int i = 0; i < length; i++) { + uint8_t head; + head = 1 & (in[i] >> 7); + opt_successor(k, s, head, &x2); - head = 1 & (in[i] >> 6); - opt_successor(k, &x2, head, s); + head = 1 & (in[i] >> 6); + opt_successor(k, &x2, head, s); - head = 1 & (in[i] >> 5); - opt_successor(k, s, head, &x2); + head = 1 & (in[i] >> 5); + opt_successor(k, s, head, &x2); - head = 1 & (in[i] >> 4); - opt_successor(k, &x2, head, s); + head = 1 & (in[i] >> 4); + opt_successor(k, &x2, head, s); - head = 1 & (in[i] >> 3); - opt_successor(k, s, head, &x2); + head = 1 & (in[i] >> 3); + opt_successor(k, s, head, &x2); - head = 1 & (in[i] >> 2); - opt_successor(k, &x2, head, s); + head = 1 & (in[i] >> 2); + opt_successor(k, &x2, head, s); - head = 1 & (in[i] >> 1); - opt_successor(k, s, head, &x2); + head = 1 & (in[i] >> 1); + opt_successor(k, s, head, &x2); - head = 1 & in[i]; - opt_successor(k, &x2, head, s); - } - - //For tag MAC, an additional 32 zeroes - if (add32Zeroes) { - for (i = 0; i < 16; i++) { - opt_successor(k, s, 0, &x2); - opt_successor(k, &x2, 0, s); - } - } + head = 1 & in[i]; + opt_successor(k, &x2, head, s); + } + + //For tag MAC, an additional 32 zeroes + if (add32Zeroes) { + for (int i = 0; i < 16; i++) { + opt_successor(k, s, 0, &x2); + opt_successor(k, &x2, 0, s); + } + } } -void opt_output(const uint8_t* k,State* s, uint8_t *buffer) { - uint8_t times = 0; - uint8_t bout = 0; - State temp = {0,0,0,0}; - for ( ; times < 4; times++) { - bout =0; - bout |= (s->r & 0x4) << 5; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) << 4; - opt_successor(k, &temp, 0, s); - bout |= (s->r & 0x4) << 3; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) << 2; - opt_successor(k, &temp, 0, s); - bout |= (s->r & 0x4) << 1; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) ; - opt_successor(k, &temp, 0, s); - bout |= (s->r & 0x4) >> 1; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) >> 2; - opt_successor(k, &temp, 0, s); - buffer[times] = bout; - } +void opt_output(const uint8_t *k, State *s, uint8_t *buffer) { + State temp = {0, 0, 0, 0}; + for (uint8_t times = 0; times < 4; times++) { + uint8_t bout = 0; + bout |= (s->r & 0x4) << 5; + opt_successor(k, s, 0, &temp); + bout |= (temp.r & 0x4) << 4; + opt_successor(k, &temp, 0, s); + bout |= (s->r & 0x4) << 3; + opt_successor(k, s, 0, &temp); + bout |= (temp.r & 0x4) << 2; + opt_successor(k, &temp, 0, s); + bout |= (s->r & 0x4) << 1; + opt_successor(k, s, 0, &temp); + bout |= (temp.r & 0x4) ; + opt_successor(k, &temp, 0, s); + bout |= (s->r & 0x4) >> 1; + opt_successor(k, s, 0, &temp); + bout |= (temp.r & 0x4) >> 2; + opt_successor(k, &temp, 0, s); + buffer[times] = bout; + } } -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 - }; +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); - opt_output(k,&_init, out); + opt_suc(k, &_init, input, 12, false); + opt_output(k, &_init, out); } uint8_t rev_byte(uint8_t b) { - b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; - b = (b & 0xCC) >> 2 | (b & 0x33) << 2; - b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - return b; + b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; + b = (b & 0xCC) >> 2 | (b & 0x33) << 2; + b = (b & 0xAA) >> 1 | (b & 0x55) << 1; + return b; } -void opt_reverse_arraybytecpy(uint8_t* dest, uint8_t *src, size_t len) { - uint8_t i; - for ( i =0; i< len ; i++) - dest[i] = rev_byte(src[i]); +void opt_reverse_arraybytecpy(uint8_t *dest, uint8_t *src, size_t len) { + uint8_t i; + for (i = 0; i < len ; i++) + dest[i] = rev_byte(src[i]); } void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { - static uint8_t cc_nr[12]; - opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12); - uint8_t dest [] = {0,0,0,0,0,0,0,0}; - opt_MAC(div_key_p, cc_nr, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest, 4); - return; + static uint8_t cc_nr[12]; + opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12); + uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0}; + opt_MAC(div_key_p, cc_nr, dest); + //The output MAC must also be reversed + opt_reverse_arraybytecpy(mac, dest, 4); + return; } void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { - static uint8_t cc_nr[8+4+4]; - opt_reverse_arraybytecpy(cc_nr, cc_p, 12); - 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_nr, 12, true); - uint8_t dest [] = {0,0,0,0}; - opt_output(div_key_p, &_init, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest,4); - return; + static uint8_t cc_nr[8 + 4 + 4]; + opt_reverse_arraybytecpy(cc_nr, cc_p, 12); + 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_nr, 12, true); + uint8_t dest [] = {0, 0, 0, 0}; + opt_output(div_key_p, &_init, dest); + //The output MAC must also be reversed + opt_reverse_arraybytecpy(mac, dest, 4); + return; } /** @@ -234,16 +231,16 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { * @return the cipher state */ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { - static uint8_t cc_nr[8]; - opt_reverse_arraybytecpy(cc_nr, cc_p, 8); - 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_nr, 8, false); - return _init; + static uint8_t cc_nr[8]; + opt_reverse_arraybytecpy(cc_nr, cc_p, 8); + 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_nr, 8, false); + return _init; } /** * The second part of the tag MAC calculation, since the CC is already calculated into the state, @@ -254,14 +251,14 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { * @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) { - static uint8_t _nr[4]; - opt_reverse_arraybytecpy(_nr, nr, 4); - opt_suc(div_key_p, &_init,_nr, 4, true); +void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { + static uint8_t _nr[4]; + opt_reverse_arraybytecpy(_nr, nr, 4); + opt_suc(div_key_p, &_init, _nr, 4, true); - uint8_t dest [] = {0,0,0,0}; - opt_output(div_key_p, &_init, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest,4); - return; + uint8_t dest [] = {0, 0, 0, 0}; + opt_output(div_key_p, &_init, dest); + //The output MAC must also be reversed + opt_reverse_arraybytecpy(mac, dest, 4); + return; } diff --git a/armsrc/optimized_cipher.h b/armsrc/optimized_cipher.h index 7398069f0..9bf0516de 100644 --- a/armsrc/optimized_cipher.h +++ b/armsrc/optimized_cipher.h @@ -8,16 +8,16 @@ /** * 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 . +* 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; + uint8_t l; + uint8_t r; + uint8_t b; + uint16_t t; } State; /** The reader MAC is MAC(key, CC * NR ) @@ -46,6 +46,6 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); * @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); +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 index 8405c96ce..942569a9c 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -3,488 +3,503 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -int DemodPCF7931(uint8_t **outBlocks) { - +size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; - uint8_t blocks[8][16]; + 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; - int 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); + int GraphTraceLen = BigBuf_max_traceLen(); + if (GraphTraceLen > 18000) + GraphTraceLen = 18000; - lmin = 64; - lmax = 192; + int i = 2, 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 = 64, lmax = 192; + uint8_t dir; - i = 2; + BigBuf_Clear_keep_EM(); + LFSetupFPGAForADC(95, true); + DoAcquisition_default(0, true); - /* 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; - } + /* 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; + 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; + 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) { + // 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 + half_switch = 0; + } else + half_switch++; + } else if (ABS(lc - clock) < tolerance) { + // 64TO bits[bitidx++] = 1; - } else { - // Error - warnings++; - if (warnings > 10) - { - Dbprintf("Error: too many detection errors, aborting..."); - return 0; - } - } + } 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; + 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; } -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; +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; } -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; +bool IsBlock1PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + if (block[10] == 0 + && block[11] == 0 + && block[12] == 0 + && block[13] == 0) { + + if ((block[14] & 0x7f) <= 9 + && block[15] <= 9) { + return true; + } + } + return false; } 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; + 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; - memset(Blocks, 0, 8*17*sizeof(uint8_t)); + size_t n = 0; // transmitted blocks + uint8_t tmp_blocks[4][16]; // temporary read buffer - 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; - } + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found + int errors = 0; // error counter + int tries = 0; // tries counter - 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("-----------------------------------------"); + memset(memory_blocks, 0, 8 * 17 * sizeof(uint8_t)); + memset(single_blocks, 0, 8 * 17 * sizeof(uint8_t)); - cmd_send(CMD_ACK,0,0,0,0,0); + 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) { + 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; + + 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); + 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); + + 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("-----------------------------------------"); + } + reply_old(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 << u)) { // bit 1 + parity++; + AddBitPCF7931(1, tab, l, p); + } else //bit 0 + AddBitPCF7931(0, tab, l, p); + } + + //parity bit + if ((parity % 2) == 0) + AddBitPCF7931(0, tab, l, p); //even parity + else + AddBitPCF7931(1, tab, l, p);//odd parity + + //time access memory + AddPatternPCF7931(5120 + 2680, 0, 0, tab); + + //conversion of the scale time + for (u = 0; u < 500; ++u) + tab[u] = (tab[u] * 3) / 2; + + //compensation of the counter reload + while (!comp) { + comp = 1; + for (u = 0; tab[u] != 0; ++u) + if (tab[u] > 0xFFFF) { + tab[u] -= 0xFFFF; + comp = 0; + } + } + + SendCmdPCF7931(tab); +} /* 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) -{ - uint32_t tab[1024] = {0}; // data times frame - uint32_t u = 0; - uint8_t parity = 0; - bool comp = 0; +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); - //BUILD OF THE DATA FRAME + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; - //alimentation of the tag (time for initializing) - AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); - - //PMC - Dbprintf("Initialization delay : %d us", init_delay); - AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); - - Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); - - //password indication bit - AddBitPCF7931(1, tab, l, p); - - //password (on 56 bits) - Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7); - AddBytePCF7931(pass1, tab, l, p); - AddBytePCF7931(pass2, tab, l, p); - AddBytePCF7931(pass3, tab, l, p); - AddBytePCF7931(pass4, tab, l, p); - AddBytePCF7931(pass5, tab, l, p); - AddBytePCF7931(pass6, tab, l, p); - AddBytePCF7931(pass7, tab, l, p); - - - //programming mode (0 or 1) - AddBitPCF7931(0, tab, l, p); - - //block adress on 6 bits - Dbprintf("Block address : %02x", address); - for (u=0; u<6; u++) - { - if (address&(1< 0xFFFF){ - tab[u] -= 0xFFFF; - comp = 0; - } - } - } - - SendCmdPCF7931(tab); + 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, tempo=0; +void SendCmdPCF7931(uint32_t *tab) { + uint16_t u = 0, tempo = 0; - Dbprintf("Sending data frame..."); + Dbprintf("Sending data frame..."); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + LED_A_ON(); - 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; - // 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 << AT91C_ID_TC0); + 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; - //initialization of the timer - AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0); - 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; - tempo = AT91C_BASE_TC0->TC_CV; - for( u = 0; tab[u] != 0; u += 3){ + // modulate antenna + HIGH(GPIO_SSC_DOUT); + while (tempo != tab[u + 2]) + tempo = AT91C_BASE_TC0->TC_CV; + } - // modulate antenna - HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; + LED_A_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - // 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 - LED(0xFFFF, 1000); + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + LED(0xFFFF, 1000); } -/* Add a byte for building the data frame of PCF7931 tags +/* 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; + } + } -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<= 'a') && ((c) <= 'z'))) /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */ -#define MAXNBUF (sizeof(intmax_t) * NBBY + 1) +#define MAXNBUF (sizeof(intmax_t) * NBBY + 1) /* * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse @@ -59,19 +59,16 @@ char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; * The buffer pointed to by `nbuf' must have length >= MAXNBUF. */ static char * -ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) -{ - char *p, c; - - p = nbuf; - *p = '\0'; - do { - c = hex2ascii(num % base); - *++p = upper ? toupper(c) : c; - } while (num /= base); - if (lenp) - *lenp = p - nbuf; - return (p); +ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) { + char *p = nbuf; + *p = '\0'; + do { + char c = hex2ascii(num % base); + *++p = upper ? toupper(c) : c; + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); } /* @@ -82,7 +79,7 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) * The format %b is supported to decode error registers. * Its usage is: * - * printf("reg=%b\n", regval, "*"); + * printf("reg=%b\n", regval, "*"); * * where is the output base expressed as a control character, e.g. * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, @@ -90,340 +87,356 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) * the next characters (up to a control character, i.e. a character <= 32), * give the name of the register. Thus: * - * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); + * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); * * would produce output: * - * reg=3 + * reg=3 * * XXX: %D -- Hexdump, takes pointer and separator string: - * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX - * ("%*D", len, ptr, " " -> XX XX XX XX ... + * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX + * ("%*D", len, ptr, " " -> XX XX XX XX ... */ int -kvsprintf(char const *fmt, void *arg, int radix, va_list ap) -{ +kvsprintf(char const *fmt, void *arg, int radix, va_list ap) { #define PCHAR(c) {int cc=(c); *d++ = cc; retval++; } - char nbuf[MAXNBUF]; - char *d; - const char *p, *percent, *q; - u_char *up; - int ch, n; - uintmax_t num; - int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; - int cflag, hflag, jflag, tflag, zflag; - int dwidth, upper; - char padc; - int stop = 0, retval = 0; + char nbuf[MAXNBUF]; + char *d; + const char *p, *percent, *q; + u_char *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int cflag, hflag, jflag, tflag, zflag; + int dwidth, upper; + char padc; + int stop = 0, retval = 0; - num = 0; - d = (char *) arg; + num = 0; + d = (char *) arg; - if (fmt == NULL) - fmt = "(fmt null)\n"; + if (fmt == NULL) + fmt = "(fmt null)\n"; - if (radix < 2 || radix > 36) - radix = 10; + if (radix < 2 || radix > 36) + radix = 10; - for (;;) { - padc = ' '; - width = 0; - while ((ch = (u_char)*fmt++) != '%' || stop) { - PCHAR(ch); - if (ch == '\0') - return (retval); - } - percent = fmt - 1; - qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; - sign = 0; dot = 0; dwidth = 0; upper = 0; - cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; -reswitch: switch (ch = (u_char)*fmt++) { - case '.': - dot = 1; - goto reswitch; - case '#': - sharpflag = 1; - goto reswitch; - case '+': - sign = 1; - goto reswitch; - case '-': - ladjust = 1; - goto reswitch; - case '%': - PCHAR(ch); - break; - case '*': - if (!dot) { - width = va_arg(ap, int); - if (width < 0) { - ladjust = !ladjust; - width = -width; - } - } else { - dwidth = va_arg(ap, int); - } - goto reswitch; - case '0': - if (!dot) { - padc = '0'; - goto reswitch; - } - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - for (n = 0;; ++fmt) { - n = n * 10 + ch - '0'; - ch = *fmt; - if (ch < '0' || ch > '9') - break; - } - if (dot) - dwidth = n; - else - width = n; - goto reswitch; - case 'b': - num = (u_int)va_arg(ap, int); - p = va_arg(ap, char *); - for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) - PCHAR(*q--); + for (;;) { + padc = ' '; + width = 0; + while ((ch = (u_char) * fmt++) != '%' || stop) { + PCHAR(ch); + if (ch == '\0') + return (retval); + } + percent = fmt - 1; + qflag = 0; + lflag = 0; + ladjust = 0; + sharpflag = 0; + neg = 0; + sign = 0; + dot = 0; + dwidth = 0; + upper = 0; + cflag = 0; + hflag = 0; + jflag = 0; + tflag = 0; + zflag = 0; +reswitch: + switch (ch = (u_char) * fmt++) { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch); + break; + case '*': + if (!dot) { + width = va_arg(ap, int); + if (width < 0) { + ladjust = !ladjust; + width = -width; + } + } else { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) { + padc = '0'; + goto reswitch; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + for (n = 0;; ++fmt) { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = (u_int)va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) + PCHAR(*q--); - if (num == 0) - break; + if (num == 0) + break; - for (tmp = 0; *p;) { - n = *p++; - if (num & (1 << (n - 1))) { - PCHAR(tmp ? ',' : '<'); - for (; (n = *p) > ' '; ++p) - PCHAR(n); - tmp = 1; - } else - for (; *p > ' '; ++p) - continue; - } - if (tmp) - PCHAR('>'); - break; - case 'c': - PCHAR(va_arg(ap, int)); - break; - case 'D': - up = va_arg(ap, u_char *); - p = va_arg(ap, char *); - if (!width) - width = 16; - while(width--) { - PCHAR(hex2ascii(*up >> 4)); - PCHAR(hex2ascii(*up & 0x0f)); - up++; - if (width) - for (q=p;*q;q++) - PCHAR(*q); - } - break; - case 'd': - case 'i': - base = 10; - sign = 1; - goto handle_sign; - case 'h': - if (hflag) { - hflag = 0; - cflag = 1; - } else - hflag = 1; - goto reswitch; - case 'j': - jflag = 1; - goto reswitch; - case 'l': - if (lflag) { - lflag = 0; - qflag = 1; - } else - lflag = 1; - goto reswitch; - case 'n': - if (jflag) - *(va_arg(ap, intmax_t *)) = retval; - else if (qflag) - *(va_arg(ap, quad_t *)) = retval; - else if (lflag) - *(va_arg(ap, long *)) = retval; - else if (zflag) - *(va_arg(ap, size_t *)) = retval; - else if (hflag) - *(va_arg(ap, short *)) = retval; - else if (cflag) - *(va_arg(ap, char *)) = retval; - else - *(va_arg(ap, int *)) = retval; - break; - case 'o': - base = 8; - goto handle_nosign; - case 'p': - base = 16; - sharpflag = (width == 0); - sign = 0; - num = (uintptr_t)va_arg(ap, void *); - goto number; - case 'q': - qflag = 1; - goto reswitch; - case 'r': - base = radix; - if (sign) - goto handle_sign; - goto handle_nosign; - case 's': - p = va_arg(ap, char *); - if (p == NULL) - p = "(null)"; - if (!dot) - n = strlen (p); - else - for (n = 0; n < dwidth && p[n]; n++) - continue; + for (tmp = 0; *p;) { + n = *p++; + if (num & (1 << (n - 1))) { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>'); + break; + case 'c': + PCHAR(va_arg(ap, int)); + break; + case 'D': + up = va_arg(ap, u_char *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while (width--) { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q = p; *q; q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'h': + if (hflag) { + hflag = 0; + cflag = 1; + } else + hflag = 1; + goto reswitch; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) { + lflag = 0; + qflag = 1; + } else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t)va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen(p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; - width -= n; + width -= n; - if (!ladjust && width > 0) - while (width--) - PCHAR(padc); - while (n--) - PCHAR(*p++); - if (ladjust && width > 0) - while (width--) - PCHAR(padc); - break; - case 't': - tflag = 1; - goto reswitch; - case 'u': - base = 10; - goto handle_nosign; - case 'X': - upper = 1; - case 'x': - base = 16; - goto handle_nosign; - case 'y': - base = 16; - sign = 1; - goto handle_sign; - case 'z': - zflag = 1; - goto reswitch; + if (!ladjust && width > 0) + while (width--) + PCHAR(padc); + while (n--) + PCHAR(*p++); + if (ladjust && width > 0) + while (width--) + PCHAR(padc); + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + case 'x': + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; handle_nosign: - sign = 0; - if (jflag) - num = va_arg(ap, uintmax_t); - else if (qflag) - num = va_arg(ap, u_quad_t); - else if (tflag) - num = va_arg(ap, ptrdiff_t); - else if (lflag) - num = va_arg(ap, u_long); - else if (zflag) - num = va_arg(ap, size_t); - else if (hflag) - num = (u_short)va_arg(ap, int); - else if (cflag) - num = (u_char)va_arg(ap, int); - else - num = va_arg(ap, u_int); - goto number; + sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, u_quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, u_long); + else if (zflag) + num = va_arg(ap, size_t); + else if (hflag) + num = (u_short)va_arg(ap, int); + else if (cflag) + num = (u_char)va_arg(ap, int); + else + num = va_arg(ap, u_int); + goto number; handle_sign: - if (jflag) - num = va_arg(ap, intmax_t); - else if (qflag) - num = va_arg(ap, quad_t); - else if (tflag) - num = va_arg(ap, ptrdiff_t); - else if (lflag) - num = va_arg(ap, long); - else if (zflag) - num = va_arg(ap, ssize_t); - else if (hflag) - num = (short)va_arg(ap, int); - else if (cflag) - num = (char)va_arg(ap, int); - else - num = va_arg(ap, int); + if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, ssize_t); + else if (hflag) + num = (short)va_arg(ap, int); + else if (cflag) + num = (char)va_arg(ap, int); + else + num = va_arg(ap, int); number: - if (sign && (intmax_t)num < 0) { - neg = 1; - num = -(intmax_t)num; - } - p = ksprintn(nbuf, num, base, &tmp, upper); - if (sharpflag && num != 0) { - if (base == 8) - tmp++; - else if (base == 16) - tmp += 2; - } - if (neg) - tmp++; + if (sign && (intmax_t)num < 0) { + neg = 1; + num = -(intmax_t)num; + } + p = ksprintn(nbuf, num, base, &tmp, upper); + if (sharpflag && num != 0) { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; - if (!ladjust && padc != '0' && width - && (width -= tmp) > 0) - while (width--) - PCHAR(padc); - if (neg) - PCHAR('-'); - if (sharpflag && num != 0) { - if (base == 8) { - PCHAR('0'); - } else if (base == 16) { - PCHAR('0'); - PCHAR('x'); - } - } - if (!ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); + if (!ladjust && padc != '0' && width + && (width -= tmp) > 0) + while (width--) + PCHAR(padc); + if (neg) + PCHAR('-'); + if (sharpflag && num != 0) { + if (base == 8) { + PCHAR('0'); + } else if (base == 16) { + PCHAR('0'); + PCHAR('x'); + } + } + if (!ladjust && width && (width -= tmp) > 0) + while (width--) + PCHAR(padc); - while (*p) - PCHAR(*p--); + while (*p) + PCHAR(*p--); - if (ladjust && width && (width -= tmp) > 0) - while (width--) - PCHAR(padc); + if (ladjust && width && (width -= tmp) > 0) + while (width--) + PCHAR(padc); - break; - default: - while (percent < fmt) - PCHAR(*percent++); - /* - * Since we ignore an formatting argument it is no - * longer safe to obey the remaining formatting - * arguments as the arguments will no longer match - * the format specs. - */ - stop = 1; - break; - } - } - PCHAR(0); - return retval; + break; + default: + while (percent < fmt) + PCHAR(*percent++); + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } + PCHAR(0); + return retval; #undef PCHAR } -int vsprintf(char *dest, const char *fmt, va_list ap) -{ - return kvsprintf(fmt, dest, 10, ap); +int vsprintf(char *dest, const char *fmt, va_list ap) { + return kvsprintf(fmt, dest, 10, ap); } int -sprintf(char *dest, const char *fmt, ...) -{ - /* http://www.pagetable.com/?p=298 */ - int retval; - va_list ap; - va_start(ap, fmt); - retval = kvsprintf(fmt, dest, 10, ap); - va_end(ap); - return retval; +sprintf(char *dest, const char *fmt, ...) { + /* http://www.pagetable.com/?p=298 */ + int retval; + va_list ap; + va_start(ap, fmt); + retval = kvsprintf(fmt, dest, 10, ap); + va_end(ap); + return retval; } diff --git a/armsrc/printf.h b/armsrc/printf.h index 4060fcd1c..ff0143790 100644 --- a/armsrc/printf.h +++ b/armsrc/printf.h @@ -15,8 +15,8 @@ #include #include "string.h" -int kvsprintf(const char *format, void *arg, int radix, va_list ap) __attribute__ ((format (printf, 1, 0))); -int vsprintf(char *str, const char *format, va_list ap) __attribute__ ((format (printf, 2, 0))); -int sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +int kvsprintf(const char *fmt, void *arg, int radix, va_list ap) __attribute__((format(printf, 1, 0))); +int vsprintf(char *dest, const char *fmt, va_list ap) __attribute__((format(printf, 2, 0))); +int sprintf(char *dest, const char *fmt, ...) __attribute__((format(printf, 2, 3))); #endif diff --git a/armsrc/start.c b/armsrc/start.c index d2e4ed4c4..94eb429ac 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -21,64 +21,62 @@ 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 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 inflate_free(voidpf opaque, voidpf address) { + // nothing to do } -static void uncompress_data_section(void) -{ - z_stream data_section; +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; + next_free_memory = BigBuf_get_addr(); - // initialize zlib for inflate - inflateInit2(&data_section, 15); + // 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; - // 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; + // initialize zlib for inflate + int res = inflateInit2(&data_section, 15); + if (res < 0) + return; + + // 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; } -void __attribute__((section(".startos"))) Vector(void) -{ - /* Stack should have been set up by the bootloader */ - // char *src; - char *dst, *end; - - uncompress_data_section(); +void __attribute__((section(".startos"))) Vector(void) { + /* Stack should have been set up by the bootloader */ + // char *src; + char *dst, *end; - /* Set up (that is: clear) BSS. */ - dst = &__bss_start__; - end = &__bss_end__; - while(dst < end) *dst++ = 0; + uncompress_data_section(); - // 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 (that is: clear) BSS. */ + dst = &__bss_start__; + end = &__bss_end__; + while (dst < end) *dst++ = 0; - AppMain(); + // 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(); } -#endif \ No newline at end of file +#endif diff --git a/armsrc/string.c b/armsrc/string.c index 6552ce1c9..5c154643c 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -9,98 +9,88 @@ //----------------------------------------------------------------------------- #include "string.h" -void *memcpy(void *dest, const void *src, int len) -{ - uint8_t *d = dest; - const uint8_t *s = src; - while((len--) > 0) { - *d = *s; - d++; - s++; - } - return dest; +void *memcpy(void *dest, const void *src, int 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, int len) -{ - uint8_t *d = dest; - while((len--) > 0) { - *d = c; - d++; - } - return dest; +void *memset(void *dest, int c, int len) { + uint8_t *d = dest; + while ((len--) > 0) { + *d = c; + d++; + } + return dest; } -int memcmp(const void *av, const void *bv, int len) -{ - const uint8_t *a = av; - const uint8_t *b = bv; +int memcmp(const void *av, const void *bv, int len) { + const uint8_t *a = av; + const uint8_t *b = bv; - while((len--) > 0) { - if(*a != *b) { - return *a - *b; - } - a++; - b++; - } - return 0; + while ((len--) > 0) { + if (*a != *b) { + return *a - *b; + } + a++; + b++; + } + return 0; } -void memxor(uint8_t * dest, uint8_t * src, size_t len) { - for( ; len > 0; len--,dest++,src++) - *dest ^= *src; +void memxor(uint8_t *dest, uint8_t *src, size_t len) { + for (; len > 0; len--, dest++, src++) + *dest ^= *src; } -int strlen(const char *str) -{ - int l = 0; - while(*str) { - l++; - str++; - } - return l; +int strlen(const char *str) { + const char *p; + for (p = str; *p != '\0'; ++p) { + } + return p - str; } -char* strncat(char *dest, const char *src, unsigned int n) -{ - unsigned int dest_len = strlen(dest); - unsigned int i; +char *strncat(char *dest, const char *src, unsigned int 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'; + for (i = 0 ; i < n && src[i] != '\0' ; i++) + dest[dest_len + i] = src[i]; + dest[dest_len + i] = '\0'; - return dest; + return dest; } -char* strcat(char *dest, const char *src) -{ - unsigned int dest_len = strlen(dest); - unsigned int i; +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'; + for (i = 0 ; src[i] != '\0' ; i++) + dest[dest_len + i] = src[i]; + dest[dest_len + i] = '\0'; - return dest; + return dest; } ////////////////////////////////////////// code to do 'itoa' /* reverse: reverse string s in place */ -void strreverse(char s[]) -{ - int c, i, j; +void strreverse(char s[]) { + int j = strlen(s) - 1; - for (i = 0, j = strlen(s)-1; i> 10; + int ticks = (48 * us) >> 10; - // Borrow a PWM unit for my real-time clock - AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); - - // 48 MHz / 1024 gives 46.875 kHz - AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register - AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register - AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register + // Borrow a PWM unit for my real-time clock + AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); - uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + // 48 MHz / 1024 gives 46.875 kHz + AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register + AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register + AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register - for(;;) { - uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - if (now == (uint16_t)(start + ticks)) - return; + uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - WDT_HIT(); - } + for (;;) { + uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + if (now == (uint16_t)(start + ticks)) + return; + + WDT_HIT(); + } } void SpinDelay(int ms) { - // convert to uS and call microsecond delay function - SpinDelayUs(ms*1000); + // convert to uS and call microsecond delay function + SpinDelayUs(ms * 1000); } // ------------------------------------------------------------------------- // 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(void) { - // 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% + // 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% } /* * Get the current count. */ -uint32_t RAMFUNC GetTickCount(void){ - return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; +uint32_t RAMFUNC GetTickCount(void) { + return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; +} + +uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) { + uint32_t stop_ticks = AT91C_BASE_RTTC->RTTC_RTVR; + if (stop_ticks > start_ticks) + return stop_ticks - start_ticks; + return (UINT32_MAX - start_ticks) + stop_ticks; } // ------------------------------------------------------------------------- -// microseconds timer +// microseconds timer // ------------------------------------------------------------------------- void StartCountUS(void) { - 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; + 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; - // fast clock - // tick=1.5mks - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - 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 | - 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_CMR = AT91C_TC_CLKS_XC1; // from timer 0 - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TCB->TCB_BCR = 1; - - while (AT91C_BASE_TC1->TC_CV > 0); + // fast clock + // tick=1.5mks + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + 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 | + 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_CMR = AT91C_TC_CLKS_XC1; // from timer 0 + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TCB->TCB_BCR = 1; + + while (AT91C_BASE_TC1->TC_CV > 0); } -uint32_t RAMFUNC GetCountUS(void){ - //return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); - // By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548 - return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3; +uint32_t RAMFUNC GetCountUS(void) { + //return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); + // By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548 + return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3; } // ------------------------------------------------------------------------- -// Timer for iso14443 commands. Uses ssp_clk from FPGA +// Timer for iso14443 commands. Uses ssp_clk from FPGA // ------------------------------------------------------------------------- void StartCountSspClk(void) { - 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_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 - // 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_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) - | 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 + // 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_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) + | 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 + // 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 - // 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 + // 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 | AT91C_TC_SWTRG; // enable and reset TC0 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1 - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2 + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2 - // synchronize the counter with the ssp_frame signal. - // Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present - 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 + // synchronize the counter with the ssp_frame signal. + // Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present + 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) 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). + // 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) 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_TC2->TC_CV > 0); + // 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_TC2->TC_CV > 0); } -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); +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 RAMFUNC GetCountSspClk(void) { - uint32_t 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); - return tmp_count; + uint32_t 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); + return tmp_count; } // ------------------------------------------------------------------------- // 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; +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; + // 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 + // 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 + // 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) + // 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); + // 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; + uint32_t hi, lo; - do { - hi = AT91C_BASE_TC1->TC_CV; - lo = AT91C_BASE_TC0->TC_CV; - } while(hi != AT91C_BASE_TC1->TC_CV); + do { + hi = AT91C_BASE_TC1->TC_CV; + lo = AT91C_BASE_TC0->TC_CV; + } while (hi != AT91C_BASE_TC1->TC_CV); - return (hi << 16) | lo; + 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); +void WaitTicks(uint32_t ticks) { + if (ticks == 0) return; + ticks += GetTicks(); + while (GetTicks() < ticks); } -// Wait / Spindelay in us (microseconds) +// Wait / Spindelay in us (microseconds) // 1us = 1.5ticks. -void WaitUS(uint16_t us){ - WaitTicks( (uint32_t)us * 3/2 ); +void WaitUS(uint16_t us) { + WaitTicks((uint32_t)us * 3 / 2); } -void WaitMS(uint16_t ms){ - WaitTicks( (uint32_t)ms * 1500 ); +void WaitMS(uint16_t ms) { + WaitTicks((uint32_t)ms * 1500); } // stop clock -void StopTicks(void){ - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; +void StopTicks(void) { + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; } diff --git a/armsrc/ticks.h b/armsrc/ticks.h index 6e5e334f0..9ff0d6000 100644 --- a/armsrc/ticks.h +++ b/armsrc/ticks.h @@ -27,6 +27,7 @@ void SpinDelayUs(int us); void StartTickCount(void); uint32_t RAMFUNC GetTickCount(void); +uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks); void StartCountUS(void); uint32_t RAMFUNC GetCountUS(void); @@ -37,11 +38,11 @@ void StartCountSspClk(); void ResetSspClk(void); uint32_t RAMFUNC 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); +void StartTicks(void); +uint32_t GetTicks(void); +void WaitTicks(uint32_t ticks); +void WaitUS(uint16_t us); +void WaitMS(uint16_t ms); -extern void StopTicks(void); -#endif \ No newline at end of file +void StopTicks(void); +#endif diff --git a/armsrc/tlv.c b/armsrc/tlv.c deleted file mode 100644 index 3da03492f..000000000 --- a/armsrc/tlv.c +++ /dev/null @@ -1,77 +0,0 @@ -#include - -int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag) -{ - uint8_t tag[TAG_LENGTH] = {0x00,0x00}; - uint16_t length = 0; - //uint8_t value[VALUE_LENGTH]; - uint8_t lenlen = 0; - int i = 0; - int z = 0; - //decode tag - tag[0] = data[0]; - if((tag[0] & TLV_TAG_NUMBER_MASK) == TLV_TAG_NUMBER_MASK) { //see subsequent bytes - i++; - tag[i] = data[i]; - //assume tag is only two bytes long for now - /* - while((data[i] & TLV_TAG_MASK) == TLV_TAG_MASK){ - i++; - tag[i] = data[i]; - } - */ - } - i++; - //decode length - if((data[i] & TLV_LENGTH_MASK) == TLV_LENGTH_MASK) { - lenlen = data[i] ^ TLV_LENGTH_MASK; - i++; - length = (uint16_t)data[i]; - z = 1; - while(z < lenlen){ - i++; - z++; - length <<= 8; - length += (uint16_t)data[i]; - } - i++; - } - else { - length = (uint16_t)data[i]; - i++; - } - //copy results into the structure and return - memcpy(returnedtag->tag, tag, TAG_LENGTH); - (*returnedtag).valuelength = length; //return length of tag value - (*returnedtag).fieldlength = length + i + 1; //return length of total field - memcpy(returnedtag->value, &(data[i]), length); - return 0; -} - -//generate a TLV tag off input data -int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t* data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen) -{ - if(!tag || !data || !outputtag || !outputtaglen) //null pointer check - return 0; - - uint8_t datafieldlen = (datalen / 128) + 1; //field length of the tag - uint8_t tlvtotallen = taglen + datafieldlen + datalen; //total length of the tag - uint8_t returnedtag[tlvtotallen]; //buffer for the returned tag - uint8_t counter = 0; - memcpy(returnedtag, tag, taglen); //copy tag into buffer - counter += taglen; - if(datalen < 128){ // 1 byte length value - returnedtag[counter++] = datalen; - } - else{ - returnedtag[counter++] = datafieldlen | 0x80; //high bit set and number of length bytes - for(uint8_t i=datafieldlen; i !=0; i--){ - returnedtag[counter++] = (datalen >> (i * 8)) & 0xFF; //get current byte - } - } - memcpy(&returnedtag[counter], data, datalen); - *outputtaglen = tlvtotallen; - memcpy(outputtag, returnedtag,tlvtotallen); - return 0; -} - diff --git a/armsrc/tlv.h b/armsrc/tlv.h deleted file mode 100644 index c90756168..000000000 --- a/armsrc/tlv.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __TLV_H -#define __TLV_H - -#include -#include -#include - -//structure buffer definitions -#define TAG_LENGTH 2 -#define VALUE_LENGTH 1024 - -//masks -//if TLV_TAG_NUMBER_MASK bits are set, refer to the next byte for the tag number -//otherwise its located in bits 1-5 -#define TLV_TAG_NUMBER_MASK 0x1f -//if TLV_DATA_MASK set then its a 'constructed data object' -//otherwise a 'primitive data object' -#define TLV_DATA_MASK 0x20 -#define TLV_TAG_MASK 0x80 -#define TLV_LENGTH_MASK 0x80 - -//tlv tag structure, tag can be max of 2 bytes, length up to 65535 and value 1024 bytes long -typedef struct { - uint8_t tag[TAG_LENGTH]; - uint16_t fieldlength; - uint16_t valuelength; - uint8_t value[VALUE_LENGTH]; -}tlvtag; - -//decode a BER TLV -extern int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag); -extern int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t*data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen); -#endif //__TLV_H diff --git a/armsrc/util.c b/armsrc/util.c index b5be57923..cad2d2ac5 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -10,251 +10,261 @@ #include "util.h" size_t nbytes(size_t nbits) { - return (nbits >> 3)+((nbits % 8) > 0); -} - -/* - ref http://www.csm.ornl.gov/~dunigan/crc.html - Returns the value v with the bottom b [0,32] bits reflected. - Example: reflect(0x3e23L,3) == 0x3e26 -*/ -uint32_t reflect(uint32_t v, int b) { - uint32_t t = v; - for ( int i = 0; i < b; ++i) { - if (t & 1) - v |= BITMASK((b-1)-i); - else - v &= ~BITMASK((b-1)-i); - t>>=1; - } - return v; -} - -uint8_t reflect8(uint8_t b) { - return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; -} -uint16_t reflect16(uint16_t b) { - uint16_t v = 0; - v |= (b & 0x8000) >> 15; - v |= (b & 0x4000) >> 13; - v |= (b & 0x2000) >> 11; - v |= (b & 0x1000) >> 9; - v |= (b & 0x0800) >> 7; - v |= (b & 0x0400) >> 5; - v |= (b & 0x0200) >> 3; - v |= (b & 0x0100) >> 1; - - v |= (b & 0x0080) << 1; - v |= (b & 0x0040) << 3; - v |= (b & 0x0020) << 5; - v |= (b & 0x0010) << 7; - v |= (b & 0x0008) << 9; - v |= (b & 0x0004) << 11; - v |= (b & 0x0002) << 13; - v |= (b & 0x0001) << 15; - return v; -} - -void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { - while (len--) { - dest[len] = (uint8_t) n; - n >>= 8; - } -} - -uint64_t bytes_to_num(uint8_t* src, size_t len) { - uint64_t num = 0; - while (len--) { - num = (num << 8) | (*src); - src++; - } - 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; -} - -int32_t le24toh (uint8_t data[3]) { - return (data[2] << 16) | (data[1] << 8) | data[0]; + return (nbits >> 3) + ((nbits % 8) > 0); } //convert hex digit to integer -uint8_t hex2int(char hexchar){ - switch(hexchar){ - case '0': return 0; break; - case '1': return 1; break; - case '2': return 2; break; - case '3': return 3; break; - case '4': return 4; break; - case '5': return 5; break; - case '6': return 6; break; - case '7': return 7; break; - case '8': return 8; break; - case '9': return 9; break; +uint8_t hex2int(char hexchar) { + switch (hexchar) { + case '0': + return 0; + break; + case '1': + return 1; + break; + case '2': + return 2; + break; + case '3': + return 3; + break; + case '4': + return 4; + break; + case '5': + return 5; + break; + case '6': + return 6; + break; + case '7': + return 7; + break; + case '8': + return 8; + break; + case '9': + return 9; + break; case 'a': - case 'A': return 10; break; + case 'A': + return 10; + break; case 'b': - case 'B': return 11; break; + case 'B': + return 11; + break; case 'c': - case 'C': return 12; break; + case 'C': + return 12; + break; case 'd': - case 'D': return 13; break; + case 'D': + return 13; + break; case 'e': - case 'E': return 14; break; + case 'E': + return 14; + break; case 'f': - case 'F': return 15; break; + case 'F': + return 15; + break; default: return 0; } } void LEDsoff() { - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); } -// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8] void LED(int led, int ms) { - if (led & LED_RED) - LED_C_ON(); - if (led & LED_ORANGE) - LED_A_ON(); - if (led & LED_GREEN) - LED_B_ON(); - if (led & LED_RED2) - LED_D_ON(); + if (led & LED_A) // Proxmark3 historical mapping: LED_ORANGE + LED_A_ON(); + if (led & LED_B) // Proxmark3 historical mapping: LED_GREEN + LED_B_ON(); + if (led & LED_C) // Proxmark3 historical mapping: LED_RED + LED_C_ON(); + if (led & LED_D) // Proxmark3 historical mapping: LED_RED2 + LED_D_ON(); - if (!ms) - return; + if (!ms) + return; - SpinDelay(ms); + SpinDelay(ms); - if (led & LED_RED) - LED_C_OFF(); - if (led & LED_ORANGE) - LED_A_OFF(); - if (led & LED_GREEN) - LED_B_OFF(); - if (led & LED_RED2) - LED_D_OFF(); + if (led & LED_A) + LED_A_OFF(); + if (led & LED_B) + LED_B_OFF(); + if (led & LED_C) + LED_C_OFF(); + if (led & LED_D) + LED_D_OFF(); } +void SpinOff(uint32_t pause) { + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + SpinDelay(pause); +} + +// 0=A, 1=B, 2=C, 3=D +void SpinErr(uint8_t led, uint32_t speed, uint8_t times) { + SpinOff(speed); + NTIME(times) { + switch (led) { + case 0: + LED_A_INV(); + break; + case 1: + LED_B_INV(); + break; + case 2: + LED_C_INV(); + break; + case 3: + LED_D_INV(); + break; + } + SpinDelay(speed); + } +} + +void SpinDown(uint32_t speed) { + SpinOff(speed); + LED_D_ON(); + SpinDelay(speed); + LED_D_OFF(); + LED_C_ON(); + SpinDelay(speed); + LED_C_OFF(); + LED_B_ON(); + SpinDelay(speed); + LED_B_OFF(); + LED_A_ON(); + SpinDelay(speed); + LED_A_OFF(); +} + +void SpinUp(uint32_t speed) { + SpinOff(speed); + LED_A_ON(); + SpinDelay(speed); + LED_A_OFF(); + LED_B_ON(); + SpinDelay(speed); + LED_B_OFF(); + LED_C_ON(); + SpinDelay(speed); + LED_C_OFF(); + LED_D_ON(); + SpinDelay(speed); + LED_D_OFF(); +} + + // Determine if a button is double clicked, single clicked, // 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) { - // Up to 500ms in between clicks to mean a double click - int ticks = (48000 * (ms ? ms : 1000)) >> 10; + // Up to 500ms in between clicks to mean a double click + int ticks = (48000 * (ms ? ms : 1000)) >> 10; - // If we're not even pressed, forget about it! - if (!BUTTON_PRESS()) - return BUTTON_NO_CLICK; + // If we're not even pressed, forget about it! + if (!BUTTON_PRESS()) + return BUTTON_NO_CLICK; - // Borrow a PWM unit for my real-time clock - AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); - // 48 MHz / 1024 gives 46.875 kHz - AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); - AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; - AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; + // Borrow a PWM unit for my real-time clock + AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); + // 48 MHz / 1024 gives 46.875 kHz + AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); + AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; + AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; - uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - int letoff = 0; - for(;;) - { - uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + int letoff = 0; + for (;;) { + uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - // We haven't let off the button yet - if (!letoff) - { - // We just let it off! - if (!BUTTON_PRESS()) - { - letoff = 1; + // We haven't let off the button yet + if (!letoff) { + // We just let it off! + if (!BUTTON_PRESS()) { + letoff = 1; - // reset our timer for 500ms - start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - ticks = (48000 * (500)) >> 10; - } + // reset our timer for 500ms + start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + ticks = (48000 * (500)) >> 10; + } - // Still haven't let it off - else - // Have we held down a full second? - if (now == (uint16_t)(start + ticks)) - return BUTTON_HOLD; - } + // Still haven't let it off + else + // Have we held down a full second? + if (now == (uint16_t)(start + ticks)) + return BUTTON_HOLD; + } - // We already let off, did we click again? - else - // Sweet, double click! - if (BUTTON_PRESS()) - return BUTTON_DOUBLE_CLICK; + // We already let off, did we click again? + else + // Sweet, double click! + if (BUTTON_PRESS()) + return BUTTON_DOUBLE_CLICK; - // Have we ran out of time to double click? - else - if (now == (uint16_t)(start + ticks)) - // At least we did a single click - return BUTTON_SINGLE_CLICK; + // Have we ran out of time to double click? + else if (now == (uint16_t)(start + ticks)) + // At least we did a single click + return BUTTON_SINGLE_CLICK; - WDT_HIT(); - } + WDT_HIT(); + } - // We should never get here - return BUTTON_ERROR; + // We should never get here + return BUTTON_ERROR; } // Determine if a button is held down int BUTTON_HELD(int ms) { - // If button is held for one second - int ticks = (48000 * (ms ? ms : 1000)) >> 10; + // If button is held for one second + int ticks = (48000 * (ms ? ms : 1000)) >> 10; - // If we're not even pressed, forget about it! - if (!BUTTON_PRESS()) - return BUTTON_NO_CLICK; + // If we're not even pressed, forget about it! + if (!BUTTON_PRESS()) + return BUTTON_NO_CLICK; - // Borrow a PWM unit for my real-time clock - AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); - // 48 MHz / 1024 gives 46.875 kHz - AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); - AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; - AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; + // Borrow a PWM unit for my real-time clock + AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); + // 48 MHz / 1024 gives 46.875 kHz + AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); + AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; + AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; - uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - for(;;) - { - uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + for (;;) { + uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - // As soon as our button let go, we didn't hold long enough - if (!BUTTON_PRESS()) - return BUTTON_SINGLE_CLICK; + // As soon as our button let go, we didn't hold long enough + if (!BUTTON_PRESS()) + return BUTTON_SINGLE_CLICK; - // Have we waited the full second? - else - if (now == (uint16_t)(start + ticks)) - return BUTTON_HOLD; + // Have we waited the full second? + else if (now == (uint16_t)(start + ticks)) + return BUTTON_HOLD; - WDT_HIT(); - } + WDT_HIT(); + } - // We should never get here - return BUTTON_ERROR; + // We should never get here + return BUTTON_ERROR; } /* Similar to FpgaGatherVersion this formats stored version information @@ -263,30 +273,38 @@ int BUTTON_HELD(int ms) { * prefix in dst. */ void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information) { - struct version_information *v = (struct version_information*)version_information; - dst[0] = 0; - strncat(dst, prefix, len-1); - if (v->magic != VERSION_INFORMATION_MAGIC) { - strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1); - return; - } - if (v->versionversion != 1) { - strncat(dst, "Version information not understood\n", len - strlen(dst) - 1); - return; - } - if (!v->present) { - strncat(dst, "Version information not available\n", len - strlen(dst) - 1); - return; - } + struct version_information *v = (struct version_information *)version_information; + dst[0] = 0; + strncat(dst, prefix, len - 1); + if (v->magic != VERSION_INFORMATION_MAGIC) { + strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1); + return; + } + if (v->versionversion != 1) { + strncat(dst, "Version information not understood\n", len - strlen(dst) - 1); + return; + } + if (!v->present) { + strncat(dst, "Version information not available\n", len - strlen(dst) - 1); + return; + } - strncat(dst, v->gitversion, len - strlen(dst) - 1); - if (v->clean == 0) { - strncat(dst, "-unclean", len - strlen(dst) - 1); - } else if (v->clean == 2) { - strncat(dst, "-suspect", len - strlen(dst) - 1); - } + strncat(dst, v->gitversion, len - strlen(dst) - 1); + if (v->clean == 0) { + strncat(dst, "-unclean", len - strlen(dst) - 1); + } else if (v->clean == 2) { + strncat(dst, "-suspect", len - strlen(dst) - 1); + } - strncat(dst, " ", len - strlen(dst) - 1); - strncat(dst, v->buildtime, len - strlen(dst) - 1); - strncat(dst, "\n", len - strlen(dst) - 1); + strncat(dst, " ", len - strlen(dst) - 1); + strncat(dst, v->buildtime, len - strlen(dst) - 1); + strncat(dst, "\n", len - strlen(dst) - 1); +} + +bool data_available(void) { +#ifdef WITH_FPC_USART_HOST + return usb_poll_validate_length() || (usart_rxdata_available() > 0); +#else + return usb_poll_validate_length(); +#endif } diff --git a/armsrc/util.h b/armsrc/util.h index 77fd81ee4..8649f0431 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -12,50 +12,86 @@ #define __UTIL_H #include "common.h" +#include "commonutil.h" #include "proxmark3.h" #include "string.h" #include "BigBuf.h" #include "ticks.h" -#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) +// Basic macros + +#ifndef SHORT_COIL +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#endif + +#ifndef OPEN_COIL +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) +#endif + +#ifndef BYTEx +#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) +#endif + +// Proxmark3 RDV4.0 LEDs +#define LED_A 1 +#define LED_B 2 +#define LED_C 4 +#define LED_D 8 + +// Proxmark3 historical LEDs +#define LED_ORANGE LED_A +#define LED_GREEN LED_B +#define LED_RED LED_C +#define LED_RED2 LED_D -#define LED_RED 1 -#define LED_ORANGE 2 -#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 -#ifndef BSWAP_16 -# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8))) +#ifndef REV8 +#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)) #endif -#ifndef BITMASK -# define BITMASK(X) (1 << (X)) + +#ifndef REV16 +#define REV16(x) (REV8(x) + (REV8 (x >> 8) << 8)) #endif -#ifndef ARRAYLEN -# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef REV32 +#define REV32(x) (REV16(x) + (REV16(x >> 16) << 16)) +#endif + +#ifndef REV64 +#define REV64(x) (REV32(x) + (REV32(x >> 32) << 32)) +#endif + +#ifndef BIT32 +#define BIT32(x,n) ((((x)[(n)>>5])>>((n)))&1) +#endif + +#ifndef INV32 +#define INV32(x,i,n) ((x)[(i)>>5]^=((uint32_t)(n))<<((i)&31)) +#endif + +#ifndef ROTL64 +#define ROTL64(x, n) ((((uint64_t)(x))<<((n)&63))+(((uint64_t)(x))>>((0-(n))&63))) #endif size_t nbytes(size_t nbits); -extern uint32_t reflect(uint32_t v, int b); // used in crc.c ... -extern uint8_t reflect8(uint8_t b); // dedicated 8bit reversal -extern uint16_t reflect16(uint16_t b); // dedicated 16bit reversal - -void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); -uint64_t bytes_to_num(uint8_t* src, size_t len); -void rol(uint8_t *data, const size_t len); -void lsl (uint8_t *data, size_t len); -int32_t le24toh (uint8_t data[3]); uint8_t hex2int(char hexchar); void LED(int led, int ms); -void LEDsoff(); +void LEDsoff(void); +void SpinOff(uint32_t pause); +void SpinErr(uint8_t led, uint32_t speed, uint8_t times); +void SpinDown(uint32_t speed); +void SpinUp(uint32_t speed); + int BUTTON_CLICKED(int ms); int BUTTON_HELD(int ms); void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); +bool data_available(void); #endif diff --git a/armsrc/vtsend.h b/armsrc/vtsend.h index 784ff3ebc..4dcb0c62b 100644 --- a/armsrc/vtsend.h +++ b/armsrc/vtsend.h @@ -78,11 +78,11 @@ int vtsend_set_cursor(vtsend_t *p, const int visible); int vtsend_reset(vtsend_t *p); int vtsend_draw_box( - vtsend_t *p, - const int x1, const int y1, const int x2, const int y2); + vtsend_t *p, + const int x1, const int y1, const int x2, const int y2); int vtsend_fill_box( - vtsend_t *p, - const int x1, const int y1, const int x2, const int y2); + vtsend_t *p, + const int x1, const int y1, const int x2, const int y2); #ifdef __cplusplus } diff --git a/bootrom/Makefile b/bootrom/Makefile index a579c46d3..afc4162a7 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -7,9 +7,8 @@ #----------------------------------------------------------------------------- # DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code -ARMSRC = -THUMBSRC = cmd.c \ - usb_cdc.c \ +ARMSRC = +THUMBSRC = usb_cdc.c \ bootrom.c ASMSRC = ram-reset.s flash-reset.s @@ -20,11 +19,15 @@ VERSIONSRC = version.c ## zeroes. As a temporary workaround, do not use thumb for the phase 2 bootloader ## -- Henryk Plötz 2009-09-01 # ARMSRC := $(ARMSRC) $(THUMBSRC) -# THUMBSRC := +# THUMBSRC := # stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS = -I. -fno-strict-aliasing -ffunction-sections -fdata-sections +# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc +APP_CFLAGS += -fno-stack-protector -fno-pie + + # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common @@ -32,25 +35,28 @@ OBJS = $(OBJDIR)/bootrom.s19 # version.c should be remade on every compilation version.c: default_version.c - perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ + $(info [=] GEN $@) + $(Q)perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ all: $(OBJS) tarbin: $(OBJS) - $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=bootrom/%) $(OBJS:%.s19=bootrom/%.elf) + $(info [=] GEN $@) + $(Q)$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=bootrom/%) $(OBJS:%.s19=bootrom/%.elf) $(OBJDIR)/bootrom.elf: $(VERSIONOBJ) $(ASMOBJ) $(ARMOBJ) $(THUMBOBJ) - $(CC) $(LDFLAGS) -Wl,-T,ldscript-flash,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) + $(info [=] LD $@) + $(Q)$(CC) $(LDFLAGS) -Wl,-T,ldscript-flash,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) clean: - $(DELETE) $(OBJDIR)$(PATHSEP)*.o - $(DELETE) $(OBJDIR)$(PATHSEP)*.elf - $(DELETE) $(OBJDIR)$(PATHSEP)*.s19 - $(DELETE) $(OBJDIR)$(PATHSEP)*.map - $(DELETE) $(OBJDIR)$(PATHSEP)*.d - $(DELETE) version.c + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.o + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.elf + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.s19 + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.map + $(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.d + $(Q)$(DELETE) version.c -.PHONY: all clean help +.PHONY: all clean help help: @echo Multi-OS Makefile, you are running on $(DETECTED_OS) @echo Possible targets: diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c index 0dcf52b28..b2811cc6d 100644 --- a/bootrom/bootrom.c +++ b/bootrom/bootrom.c @@ -8,19 +8,46 @@ #include #include "usb_cdc.h" -#include "cmd.h" struct common_area common_area __attribute__((section(".commonarea"))); unsigned int start_addr, end_addr, bootrom_unlocked; extern char _bootrom_start, _bootrom_end, _flash_start, _flash_end; extern uint32_t _osimage_entry; +static int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) { + PacketResponseOLD txcmd; + + for (size_t i = 0; i < sizeof(PacketResponseOLD); i++) + ((uint8_t *)&txcmd)[i] = 0x00; + + // Compose the outgoing command frame + txcmd.cmd = cmd; + txcmd.arg[0] = arg0; + txcmd.arg[1] = arg1; + txcmd.arg[2] = arg2; + + // Add the (optional) content to the frame, with a maximum size of PM3_CMD_DATA_SIZE + if (data && len) { + len = MIN(len, PM3_CMD_DATA_SIZE); + for (size_t i = 0; i < len; i++) { + txcmd.d.asBytes[i] = ((uint8_t *)data)[i]; + } + } + + int result = PM3_EUNDEF; + // Send frame and make sure all bytes are transmitted + + result = usb_write((uint8_t *)&txcmd, sizeof(PacketResponseOLD)); + + return result; +} + void DbpString(char *str) { - byte_t len = 0; - while (str[len] != 0x00) - len++; - - cmd_send(CMD_DEBUG_PRINT_STRING, len, 0, 0, (byte_t*)str, len); + uint8_t len = 0; + while (str[len] != 0x00) + len++; + + reply_old(CMD_DEBUG_PRINT_STRING, len, 0, 0, (uint8_t *)str, len); } static void ConfigClocks(void) { @@ -30,193 +57,204 @@ static void ConfigClocks(void) { // enable system clock and USB clock AT91C_BASE_PMC->PMC_SCER |= AT91C_PMC_PCK | AT91C_PMC_UDP; - // enable the clock to the following peripherals + // enable the clock to the following peripherals AT91C_BASE_PMC->PMC_PCER = - (1<PMC_MOR = AT91C_CKGR_MOSCEN | PMC_MAIN_OSC_STARTUP_DELAY(8); - // wait for main oscillator to stabilize - while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS) ) {}; + // wait for main oscillator to stabilize + while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS)) {}; // PLL output clock frequency in range 80 - 160 MHz needs CKGR_PLL = 00 // PLL output clock frequency in range 150 - 180 MHz needs CKGR_PLL = 10 // PLL output is MAINCK * multiplier / divisor = 16Mhz * 12 / 2 = 96Mhz AT91C_BASE_PMC->PMC_PLLR = - PMC_PLL_DIVISOR(2) | - //PMC_PLL_COUNT_BEFORE_LOCK(0x10) | - PMC_PLL_COUNT_BEFORE_LOCK(0x3F) | - PMC_PLL_FREQUENCY_RANGE(0) | - PMC_PLL_MULTIPLIER(12) | - PMC_PLL_USB_DIVISOR(1); + PMC_PLL_DIVISOR(2) | + //PMC_PLL_COUNT_BEFORE_LOCK(0x10) | + PMC_PLL_COUNT_BEFORE_LOCK(0x3F) | + PMC_PLL_FREQUENCY_RANGE(0) | + PMC_PLL_MULTIPLIER(12) | + PMC_PLL_USB_DIVISOR(1); - // wait for PLL to lock - while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK) ) {}; + // wait for PLL to lock + while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK)) {}; - // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz - // datasheet recommends that this register is programmed in two operations - // when changing to PLL, program the prescaler first then the source + // we want a master clock (MCK) to be PLL clock / 2 = 96Mhz / 2 = 48Mhz + // datasheet recommends that this register is programmed in two operations + // when changing to PLL, program the prescaler first then the source AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2; - // wait for main clock ready signal - while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) ) {}; + // wait for main clock ready signal + while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY)) {}; - // set the source to PLL + // set the source to PLL AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2 | AT91C_PMC_CSS_PLL_CLK; - // wait for main clock ready signal - while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) ) {}; + // wait for main clock ready signal + while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY)) {}; } static void Fatal(void) { - for(;;) {}; + for (;;) {}; } void UsbPacketReceived(uint8_t *packet, int len) { - int i, dont_ack = 0; - UsbCommand* c = (UsbCommand *)packet; - volatile uint32_t *p; + int i, dont_ack = 0; + PacketCommandOLD *c = (PacketCommandOLD *)packet; - //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; - if(common_area.flags.osimage_present) - arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT; - - cmd_send(CMD_DEVICE_INFO,arg0,1,2,0,0); - } break; - - case CMD_SETUP_WRITE: { - /* The temporary write buffer of the embedded flash controller is mapped to the - * whole memory region, only the last 8 bits are decoded. - */ - p = (volatile uint32_t *)&_flash_start; - for(i = 0; i < 12; i++) - p[i+arg0] = c->d.asDwords[i]; - } break; - - case CMD_FINISH_WRITE: { - uint32_t* flash_mem = (uint32_t*)(&_flash_start); - for ( int j=0; j<2; j++) { - for(i = 0+(64*j); i < 64+(64*j); i++) { - flash_mem[i] = c->d.asDwords[i]; - } - - uint32_t flash_address = arg0 + (0x100*j); - - /* Check that the address that we are supposed to write to is within our allowed region */ - if( ((flash_address + AT91C_IFLASH_PAGE_SIZE - 1) >= end_addr) || (flash_address < start_addr) ) { - /* Disallow write */ - dont_ack = 1; - 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; - } - - // Wait until flashing of page finishes - uint32_t sr; - while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY)); - if(sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { - dont_ack = 1; - cmd_send(CMD_NACK,sr,0,0,0,0); - } - } - } break; - - case CMD_HARDWARE_RESET: { - usb_disable(); - AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; - } break; - - case CMD_START_FLASH: { - if (c->arg[2] == START_FLASH_MAGIC) - bootrom_unlocked = 1; - else - bootrom_unlocked = 0; - - int prot_start = (int)&_bootrom_start; - int prot_end = (int)&_bootrom_end; - int allow_start = (int)&_flash_start; - int allow_end = (int)&_flash_end; - int cmd_start = c->arg[0]; - int cmd_end = c->arg[1]; + //if ( len != sizeof(PacketCommandOLD`)) Fatal(); - /* Only allow command if the bootrom is unlocked, or the parameters are outside of the protected - * bootrom area. In any case they must be within the flash area. - */ - if( (bootrom_unlocked || ((cmd_start >= prot_end) || (cmd_end < prot_start))) && - (cmd_start >= allow_start) && - (cmd_end <= allow_end) ) { - start_addr = cmd_start; - end_addr = cmd_end; - } else { - start_addr = end_addr = 0; - dont_ack = 1; - cmd_send(CMD_NACK,0,0,0,0,0); - } - } break; - - default: { - Fatal(); - } break; - } - - if (!dont_ack) - cmd_send(CMD_ACK,arg0,0,0,0,0); + 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; + if (common_area.flags.osimage_present) + arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT; + + reply_old(CMD_DEVICE_INFO, arg0, 1, 2, 0, 0); + } + break; + + case CMD_SETUP_WRITE: { + /* The temporary write buffer of the embedded flash controller is mapped to the + * whole memory region, only the last 8 bits are decoded. + */ + volatile uint32_t *p = (volatile uint32_t *)&_flash_start; + for (i = 0; i < 12; i++) + p[i + arg0] = c->d.asDwords[i]; + } + break; + + case CMD_FINISH_WRITE: { + uint32_t *flash_mem = (uint32_t *)(&_flash_start); + for (int j = 0; j < 2; j++) { + for (i = 0 + (64 * j); i < 64 + (64 * j); i++) { + flash_mem[i] = c->d.asDwords[i]; + } + + uint32_t flash_address = arg0 + (0x100 * j); + + /* Check that the address that we are supposed to write to is within our allowed region */ + if (((flash_address + AT91C_IFLASH_PAGE_SIZE - 1) >= end_addr) || (flash_address < start_addr)) { + /* Disallow write */ + dont_ack = 1; + reply_old(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; + } + + // Wait until flashing of page finishes + uint32_t sr; + while (!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY)); + if (sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { + dont_ack = 1; + reply_old(CMD_NACK, sr, 0, 0, 0, 0); + } + } + } + break; + + case CMD_HARDWARE_RESET: { + usb_disable(); + AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; + } + break; + + case CMD_START_FLASH: { + if (c->arg[2] == START_FLASH_MAGIC) + bootrom_unlocked = 1; + else + bootrom_unlocked = 0; + + int prot_start = (int)&_bootrom_start; + int prot_end = (int)&_bootrom_end; + int allow_start = (int)&_flash_start; + int allow_end = (int)&_flash_end; + int cmd_start = c->arg[0]; + int cmd_end = c->arg[1]; + + /* Only allow command if the bootrom is unlocked, or the parameters are outside of the protected + * bootrom area. In any case they must be within the flash area. + */ + if ((bootrom_unlocked || ((cmd_start >= prot_end) || (cmd_end < prot_start))) && + (cmd_start >= allow_start) && + (cmd_end <= allow_end)) { + start_addr = cmd_start; + end_addr = cmd_end; + } else { + start_addr = end_addr = 0; + dont_ack = 1; + reply_old(CMD_NACK, 0, 0, 0, 0, 0); + } + } + break; + + default: { + Fatal(); + } + break; + } + + if (!dont_ack) + reply_old(CMD_ACK, arg0, 0, 0, 0, 0); } -static void flash_mode(int externally_entered) { - start_addr = 0; - end_addr = 0; - bootrom_unlocked = 0; - byte_t rx[sizeof(UsbCommand)]; +static void flash_mode(void) { + start_addr = 0; + end_addr = 0; + bootrom_unlocked = 0; + uint8_t rx[sizeof(PacketCommandOLD)]; + common_area.command = COMMON_AREA_COMMAND_NONE; + if (!common_area.flags.button_pressed && BUTTON_PRESS()) + common_area.flags.button_pressed = 1; - usb_enable(); - - // wait for reset to be complete? - for (volatile size_t i=0; i<0x100000; i++) {}; + usb_enable(); - for(;;) { - WDT_HIT(); - - // Check if there is a usb packet available - if ( cmd_receive( (UsbCommand*)rx ) ) - UsbPacketReceived(rx, sizeof(UsbCommand) ); - - if (!externally_entered && !BUTTON_PRESS()) { - /* Perform a reset to leave flash mode */ - usb_disable(); - LED_B_ON(); - AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; - for(;;) {}; - } - if (externally_entered && BUTTON_PRESS()) { - /* Let the user's button press override the automatic leave */ - externally_entered = 0; - } - } + // wait for reset to be complete? + for (volatile size_t i = 0; i < 0x100000; i++) {}; + + for (;;) { + WDT_HIT(); + + // Check if there is a usb packet available + if (usb_poll_validate_length()) { + if (usb_read(rx, sizeof(rx))) { + UsbPacketReceived(rx, sizeof(rx)); + } + } + + if (common_area.flags.button_pressed && !BUTTON_PRESS()) { + common_area.flags.button_pressed = 0; + } + if (!common_area.flags.button_pressed && BUTTON_PRESS()) { + /* Perform a reset to leave flash mode */ + common_area.flags.button_pressed = 1; + usb_disable(); + LED_B_ON(); + AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; + for (;;) {}; + } + } } void BootROM(void) { @@ -227,54 +265,54 @@ void BootROM(void) { // Kill all the pullups, especially the one on USB D+; leave them for // the unused pins, though. AT91C_BASE_PIOA->PIO_PPUDR = - GPIO_USB_PU | - GPIO_LED_A | - GPIO_LED_B | - GPIO_LED_C | - GPIO_LED_D | - GPIO_FPGA_DIN | - GPIO_FPGA_DOUT | - GPIO_FPGA_CCLK | - GPIO_FPGA_NINIT | - GPIO_FPGA_NPROGRAM | - GPIO_FPGA_DONE | - GPIO_MUXSEL_HIPKD | - GPIO_MUXSEL_HIRAW | - GPIO_MUXSEL_LOPKD | - GPIO_MUXSEL_LORAW | - GPIO_RELAY | - GPIO_NVDD_ON; - // (and add GPIO_FPGA_ON) - // These pins are outputs + GPIO_USB_PU | + GPIO_LED_A | + GPIO_LED_B | + GPIO_LED_C | + GPIO_LED_D | + GPIO_FPGA_DIN | + GPIO_FPGA_DOUT | + GPIO_FPGA_CCLK | + GPIO_FPGA_NINIT | + GPIO_FPGA_NPROGRAM | + GPIO_FPGA_DONE | + GPIO_MUXSEL_HIPKD | + GPIO_MUXSEL_HIRAW | + GPIO_MUXSEL_LOPKD | + GPIO_MUXSEL_LORAW | + GPIO_RELAY | + GPIO_NVDD_ON; + // (and add GPIO_FPGA_ON) + // These pins are outputs AT91C_BASE_PIOA->PIO_OER = - GPIO_LED_A | - GPIO_LED_B | - GPIO_LED_C | - GPIO_LED_D | - GPIO_RELAY | - GPIO_NVDD_ON; - // PIO controls the following pins + GPIO_LED_A | + GPIO_LED_B | + GPIO_LED_C | + GPIO_LED_D | + GPIO_RELAY | + GPIO_NVDD_ON; + // PIO controls the following pins AT91C_BASE_PIOA->PIO_PER = - GPIO_USB_PU | - GPIO_LED_A | - GPIO_LED_B | - GPIO_LED_C | - GPIO_LED_D; + GPIO_USB_PU | + GPIO_LED_A | + GPIO_LED_B | + GPIO_LED_C | + GPIO_LED_D; - // USB_D_PLUS_PULLUP_OFF(); - usb_disable(); - LED_D_OFF(); - LED_C_ON(); - LED_B_OFF(); - LED_A_OFF(); + // USB_D_PLUS_PULLUP_OFF(); + usb_disable(); + LED_D_OFF(); + LED_C_ON(); + LED_B_OFF(); + LED_A_OFF(); - // Set the first 256kb memory flashspeed - AT91C_BASE_EFC0->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48); + // Set the first 256kb memory flashspeed + AT91C_BASE_EFC0->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48); - // 9 = 256, 10+ is 512kb - uint8_t id = ( *(AT91C_DBGU_CIDR) & 0xF00) >> 8; - if ( id > 9 ) - AT91C_BASE_EFC1->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48); + // 9 = 256, 10+ is 512kb + uint8_t id = (*(AT91C_DBGU_CIDR) & 0xF00) >> 8; + if (id > 9) + AT91C_BASE_EFC1->EFC_FMR = AT91C_MC_FWS_1FWS | MC_FLASH_MODE_MASTER_CLK_IN_MHZ(48); // Initialize all system clocks ConfigClocks(); @@ -283,39 +321,37 @@ void BootROM(void) { int common_area_present = 0; switch (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_RSTTYP) { - case AT91C_RSTC_RSTTYP_WATCHDOG: - case AT91C_RSTC_RSTTYP_SOFTWARE: - case AT91C_RSTC_RSTTYP_USER: - /* In these cases the common_area in RAM should be ok, retain it if it's there */ - if(common_area.magic == COMMON_AREA_MAGIC && common_area.version == 1) - common_area_present = 1; - break; - default: /* Otherwise, initialize it from scratch */ - break; + case AT91C_RSTC_RSTTYP_WATCHDOG: + case AT91C_RSTC_RSTTYP_SOFTWARE: + case AT91C_RSTC_RSTTYP_USER: + /* In these cases the common_area in RAM should be ok, retain it if it's there */ + if (common_area.magic == COMMON_AREA_MAGIC && common_area.version == 1) + common_area_present = 1; + break; + default: /* Otherwise, initialize it from scratch */ + break; } - if (!common_area_present){ - /* Common area not ok, initialize it */ - int i; - /* Makeshift memset, no need to drag util.c into this */ - for(i=0; ibootphase1 :phase1 + . = LENGTH(bootphase1) - 0x4; + LONG(_version_information_start); + } >bootphase1 :phase1 - .bootphase2 : { - *(.startphase2) - *(.text) - *(.text.*) - *(.eh_frame) - *(.glue_7) - *(.glue_7t) - *(.rodata) - *(.rodata.*) - *(.data) - *(.data.*) - . = ALIGN(4); - } >ram AT>bootphase2 :phase2 + .bootphase2 : { + *(.startphase2) + *(.text) + *(.text.*) + *(.eh_frame) + *(.glue_7) + *(.glue_7t) + *(.rodata) + *(.rodata.*) + *(.data) + *(.data.*) + . = ALIGN(4); + } >ram AT>bootphase2 :phase2 - __bootphase2_src_start__ = LOADADDR(.bootphase2); - __bootphase2_start__ = ADDR(.bootphase2); - __bootphase2_end__ = __bootphase2_start__ + SIZEOF(.bootphase2); + __bootphase2_src_start__ = LOADADDR(.bootphase2); + __bootphase2_start__ = ADDR(.bootphase2); + __bootphase2_end__ = __bootphase2_start__ + SIZEOF(.bootphase2); - .bss : { - __bss_start__ = .; - *(.bss) - *(.bss.*) - . = ALIGN(4); - __bss_end__ = .; - } >ram AT>ram :bss + .bss : { + __bss_start__ = .; + *(.bss) + *(.bss.*) + . = ALIGN(4); + __bss_end__ = .; + } >ram AT>ram :bss - .commonarea (NOLOAD) : { - *(.commonarea) - } >commonarea + .commonarea (NOLOAD) : { + *(.commonarea) + } >commonarea } diff --git a/bootrom/ram-reset.s b/bootrom/ram-reset.s index ade70d8cc..ab57ee29a 100644 --- a/bootrom/ram-reset.s +++ b/bootrom/ram-reset.s @@ -14,7 +14,7 @@ .global ram_start ram_start: - ldr sp, =_stack_end - bl BootROM + ldr sp, =_stack_end + bl BootROM - .ltorg + .ltorg diff --git a/client/Makefile b/client/Makefile index af2efb26c..c3300b0cd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -9,6 +9,12 @@ # Add -DNOFORCE to disable the -F switch # Add -DPRESETS to compile with preset models (edit config.h) +# Hide full compilation line: +ifneq ($(V),1) + Q?=@ +endif +# To see full command lines, use make V=1 + CC = gcc CXX = g++ LD = g++ @@ -20,23 +26,39 @@ MV = mv ENV_LDFLAGS := $(LDFLAGS) ENV_CFLAGS := $(CFLAGS) +platform = $(shell uname) + VPATH = ../common ../zlib ../uart 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 +LIBS = -I../zlib -I../uart -I../liblua -I$(MBEDTLSLIBPATH) -I$(JANSSONLIBPATH) -I$(CBORLIBPATH) +INCLUDES_CLIENT = -I. -I../include -I../common -I/opt/local/include $(LIBS) LDFLAGS = $(ENV_LDFLAGS) -INCLUDES_CLIENT = -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua + CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -DPRESETS $(INCLUDES_CLIENT) -Wall -g -O3 +ifneq (,$(findstring MINGW,$(platform))) + CFLAGS += -mno-ms-bitfields +endif CXXFLAGS = -I../include -Wall -O3 LUAPLATFORM = generic -platform = $(shell uname) -ifneq (,$(findstring MINGW,$(platform))) +ifneq (,$(findstring MINGW,$(platform))) LUAPLATFORM = mingw - else - ifeq ($(platform),Darwin) +else + ifeq ($(platform),Darwin) LUAPLATFORM = macosx + OBJCSRCS = util_darwin.m + LDFLAGS += -framework Foundation -framework AppKit + LDLIBS := -L/usr/local/opt/readline/lib $(LDLIBS) + LIBS := -I/usr/local/opt/readline/include $(LIBS) else LUALIB += -ldl LDLIBS += -ltermcap -lncurses @@ -50,27 +72,27 @@ 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) +# 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 + 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 + 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 @@ -81,139 +103,147 @@ else QTGUIOBJS = $(OBJDIR)/guidummy.o endif -# RDV40 flag enables flashmemory commands in client. comment out if you don't have rdv40 -CFLAGS += -DWITH_FLASH -DWITH_SMARTCARD - # 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_posix.c \ - uart_win32.c \ - ui.c \ - util.c \ - util_posix.c \ - scandir.c + uart_win32.c \ + ui.c \ + commonutil.c \ + util.c \ + util_posix.c \ + scandir.c \ + crc16.c \ + comms.c -CMDSRCS = crapto1/crapto1.c \ - crapto1/crypto1.c \ - mfkey.c \ - tea.c \ - polarssl/des.c \ - polarssl/aes.c \ - polarssl/bignum.c \ - polarssl/rsa.c \ - polarssl/sha1.c \ - polarssl/sha256.c \ - polarssl/base64.c \ - loclass/cipher.c \ - loclass/cipherutils.c \ - loclass/ikeys.c \ - loclass/hash1_brute.c \ - loclass/elite_crack.c \ - loclass/fileutils.c \ - whereami.c \ - mifarehost.c \ - parity.c \ - crc.c \ - crc16.c \ - crc64.c \ - legic_prng.c \ - iso15693tools.c \ - prng.c \ - graph.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/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 \ - cmdanalyse.c \ - cmdhf.c \ - cmdhflist.c \ - cmdhf14a.c \ - cmdhf14b.c \ - cmdhf15.c \ - cmdhfepa.c \ - cmdhflegic.c \ - cmdhficlass.c \ - cmdhfmf.c \ +CMDSRCS = crapto1/crapto1.c \ + crapto1/crypto1.c \ + mifare/mfkey.c \ + tea.c \ + fido/additional_ca.c \ + fido/cose.c \ + fido/cbortools.c \ + fido/fidocore.c \ + crypto/asn1dump.c \ + crypto/libpcrypto.c\ + crypto/asn1utils.c\ + cliparser/argtable3.c\ + cliparser/cliparser.c\ + loclass/cipher.c \ + loclass/cipherutils.c \ + loclass/ikeys.c \ + loclass/elite_crack.c \ + loclass/fileutils.c \ + whereami.c \ + mifare/mifarehost.c \ + parity.c \ + crc.c \ + crc64.c \ + legic_prng.c \ + iso15693tools.c \ + prng.c \ + graph.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 \ + mifare/mifare4.c \ + mifare/mad.c \ + mifare/ndef.c \ + cmdanalyse.c \ + cmdhf.c \ + cmdhflist.c \ + cmdhf14a.c \ + cmdhf14b.c \ + cmdhf15.c \ + cmdhfepa.c \ + cmdhflegic.c \ + cmdhficlass.c \ + cmdhfmf.c \ cmdhfmfu.c \ - cmdhfmfhard.c \ + cmdhfmfp.c \ + cmdhfmfhard.c \ hardnested/hardnested_bruteforce.c \ - cmdhfmfdes.c \ - cmdhftopaz.c \ - cmdhffelica.c \ - cmdhw.c \ - cmdlf.c \ - cmdlfawid.c \ - cmdlfcotag.c \ - cmdlfem4x.c \ - cmdlffdx.c \ - cmdlfguard.c \ - cmdlfhid.c \ - cmdlfhitag.c \ - cmdlfio.c \ - cmdlfindala.c \ - cmdlfjablotron.c \ - cmdlfnexwatch.c \ - cmdlfnedap.c \ - cmdlfnoralsy.c \ - cmdlfpac.c \ - cmdlfparadox.c \ - cmdlfpcf7931.c \ - cmdlfpresco.c \ - cmdlfpyramid.c \ - cmdlfsecurakey.c \ - cmdlft55xx.c \ - cmdlfti.c \ - cmdlfviking.c \ - cmdlfvisa2000.c \ - cmdtrace.c \ - cmdflashmem.c \ - cmdsmartcard.c \ - cmdparser.c \ - cmdmain.c \ - pm3_binlib.c \ - scripting.c \ - cmdscript.c \ - pm3_bitlib.c \ - protocols.c \ - cmdcrc.c \ - reveng/preset.c \ - reveng/reveng.c \ - reveng/cli.c \ - reveng/bmpbit.c \ - reveng/model.c \ - reveng/poly.c \ - reveng/getopt.c \ - bucketsort.c + cmdhfmfdes.c \ + cmdhftopaz.c \ + cmdhffido.c \ + cmdhffelica.c \ + cmdhw.c \ + cmdlf.c \ + cmdlfawid.c \ + cmdlfcotag.c \ + cmdlfem4x.c \ + cmdlffdx.c \ + cmdlfguard.c \ + cmdlfhid.c \ + cmdlfhitag.c \ + cmdlfio.c \ + cmdlfindala.c \ + cmdlfjablotron.c \ + cmdlfkeri.c \ + cmdlfnexwatch.c \ + cmdlfnedap.c \ + cmdlfnoralsy.c \ + cmdlfpac.c \ + cmdlfparadox.c \ + cmdlfpcf7931.c \ + cmdlfpresco.c \ + cmdlfpyramid.c \ + cmdlfsecurakey.c \ + cmdlft55xx.c \ + cmdlfti.c \ + cmdlfviking.c \ + cmdlfvisa2000.c \ + cmdtrace.c \ + cmdflashmem.c \ + cmdsmartcard.c \ + cmdusart.c \ + cmdparser.c \ + cmdmain.c \ + pm3_binlib.c \ + scripting.c \ + cmdscript.c \ + pm3_bitlib.c \ + protocols.c \ + cmdcrc.c \ + reveng/preset.c \ + reveng/reveng.c \ + reveng/cli.c \ + reveng/bmpbit.c \ + reveng/model.c \ + reveng/poly.c \ + bucketsort.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) - MULTIARCHSRCS = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c + 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 + 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 + 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 @@ -222,12 +252,13 @@ 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) + $(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" ) @@ -238,91 +269,133 @@ 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) + 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) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua lualibs/mf_default_keys.lua +CLEAN = $(BINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/pm3_cmd.lua lualibs/mf_default_keys.lua # need to assign dependancies to build these first... -all: lua_build $(BINS) +all: lua_build jansson_build mbedtls_build cbor_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) all-static: proxmark3 flasher fpga_compress -proxmark3: LDLIBS+=$(LUALIB) $(QTLDLIBS) -proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua lualibs/mf_default_keys.lua - $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ - -flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ +proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) +proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/pm3_cmd.lua lualibs/mf_default_keys.lua + $(info [=] LD $@) + $(Q)$(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ + +flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS) $(OBJCOBJS) + $(info [=] LD $@) + $(Q)$(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ fpga_compress: $(OBJDIR)/fpga_compress.o $(ZLIBOBJS) - $(LD) $(LDFLAGS) $(ZLIBFLAGS) $^ $(LDLIBS) -o $@ + $(info [=] LD $@) + $(Q)$(LD) $(LDFLAGS) $(ZLIBFLAGS) $^ $(LDLIBS) -o $@ proxgui.cpp: ui/ui_overlays.h proxguiqt.moc.cpp: proxguiqt.h - $(MOC) -o$@ $^ + $(info [-] MOC $@) + $(Q)$(MOC) -o$@ $^ ui/ui_overlays.h: ui/overlays.ui - $(UIC) $^ > $@ + $(info [-] UIC $@) + $(Q)$(UIC) $^ > $@ -lualibs/usb_cmd.lua: ../include/usb_cmd.h - awk -f usb_cmd_h2lua.awk $^ > $@ +lualibs/pm3_cmd.lua: ../include/pm3_cmd.h + $(info [=] GEN $@) + $(Q)awk -f pm3_cmd_h2lua.awk $^ > $@ lualibs/mf_default_keys.lua : default_keys.dic - awk -f default_keys_dic2lua.awk $^ > $@ - + $(info [=] GEN $@) + $(Q)awk -f default_keys_dic2lua.awk $^ > $@ + clean: - $(RM) $(CLEAN) - cd ../liblua && make clean + $(Q)$(RM) $(CLEAN) + $(Q)$(MAKE) --no-print-directory -C ../liblua clean + $(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) clean + $(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) clean + $(Q)$(MAKE) --no-print-directory -C $(CBORLIBPATH) clean tarbin: $(BINS) - $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) + $(info [=] TAR ../proxmark3-$(platform)-bin.tar) + $(Q)$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) lua_build: - @echo Compiling liblua, using platform $(LUAPLATFORM) - cd ../liblua && make $(LUAPLATFORM) + $(info [*] MAKE liblua for $(LUAPLATFORM)) + $(Q)$(MAKE) --no-print-directory -C ../liblua $(LUAPLATFORM) + +jansson_build: + $(info [*] MAKE jansson) + $(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) all + +mbedtls_build: + $(info [*] MAKE mbedtls) + $(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) all + +cbor_build: + $(info [*] MAKE tinycbor) + $(Q)$(MAKE) --no-print-directory -C $(CBORLIBPATH) all .PHONY: all clean # easy printing of MAKE VARIABLES -print-%: ; @echo $* = $($*) +print-%: ; @echo $* = $($*) -$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_NOSIMD) -c -o $@ $< +$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%_NOSIMD.d + $(info [-] CC(NOSIMD) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_NOSIMD.Td) $(CFLAGS) $(HARD_SWITCH_NOSIMD) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_NOSIMD.Td $(OBJDIR)/$*_NOSIMD.d -$(OBJDIR)/%_MMX.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_MMX) -c -o $@ $< +$(OBJDIR)/%_MMX.o : %.c $(OBJDIR)/%_MMX.d + $(info [-] CC(MMX) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_MMX.Td) $(CFLAGS) $(HARD_SWITCH_MMX) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_MMX.Td $(OBJDIR)/$*_MMX.d -$(OBJDIR)/%_SSE2.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $< +$(OBJDIR)/%_SSE2.o : %.c $(OBJDIR)/%_SSE2.d + $(info [-] CC(SSE2) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_SSE2.Td) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_SSE2.Td $(OBJDIR)/$*_SSE2.d -$(OBJDIR)/%_AVX.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $< +$(OBJDIR)/%_AVX.o : %.c $(OBJDIR)/%_AVX.d + $(info [-] CC(AVX) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_AVX.Td) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_AVX.Td $(OBJDIR)/$*_AVX.d -$(OBJDIR)/%_AVX2.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $< +$(OBJDIR)/%_AVX2.o : %.c $(OBJDIR)/%_AVX2.d + $(info [-] CC(AVX2) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_AVX2.Td) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_AVX2.Td $(OBJDIR)/$*_AVX2.d -$(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $< +$(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%_AVX512.d + $(info [-] CC(AVX512) $<) + $(Q)$(CC) $(DEPFLAGS:%.Td=%_AVX512.Td) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $< + $(Q)$(MV) -f $(OBJDIR)/$*_AVX512.Td $(OBJDIR)/$*_AVX512.d %.o: %.c $(OBJDIR)/%.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $< - $(POSTCOMPILE) + $(info [-] CC $<) + $(Q)$(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $< + $(Q)$(POSTCOMPILE) %.o: %.cpp $(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d - $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(QTINCLUDES) -c -o $@ $< - $(POSTCOMPILE) + $(info [-] CXX $<) + $(Q)$(CXX) $(DEPFLAGS) $(CXXFLAGS) $(QTINCLUDES) -c -o $@ $< + $(Q)$(POSTCOMPILE) + +%.o: %.m +$(OBJDIR)/%.o : %.m $(OBJDIR)/%.d + $(info [-] CC $<) + $(Q)$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $< + $(Q)$(POSTCOMPILE) #$(CMDOBJS) $(COREOBJS): $(notdir $(%.c)) %.d # $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $< @@ -336,8 +409,10 @@ $(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d # $(CXX) $(DEPFLAGS) $(CXXFLAGS) -c -o $@ $< # $(POSTCOMPILE) -DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBSRCS) $(MULTIARCHSRCS)) \ +DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBSRCS)) \ + $(patsubst %.o, %.d, $(MULTIARCHOBJS)) \ $(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): ; diff --git a/client/aidlist.json b/client/aidlist.json new file mode 100644 index 000000000..7ec139d46 --- /dev/null +++ b/client/aidlist.json @@ -0,0 +1 @@ +[{"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "315041592E5359532E4444463031", "Type": "", "Name": "Visa Payment System Environment - PSE (1PAY.SYS.DDF01)"}, {"Vendor": "Visa International", "Description": "Visa payWave for Mobile", "Country": "United States", "AID": "325041592E5359532E4444463031", "Type": "", "Name": "Visa Proximity Payment System Environment - PPSE (2PAY.SYS.DDF01)"}, {"Vendor": "DeviceFidelity", "Description": "http://www.nfcworld.com/2010/11/24/35207/devicefidelity-adds-nfc-support-for-android-and-mifare/", "Country": "United States", "AID": "44464D46412E44466172653234313031", "Type": "", "Name": "DeviceFidelity In2Pay DFare applet"}, {"Vendor": "PBS Danmnt A/S", "Description": "(Unlicensed use of this RID. Proposal to use A000000323 instead)", "Country": "Denmark", "AID": "A00000000101", "Type": "", "Name": "MUSCLE Card Applet"}, {"Vendor": "Visa International", "Description": "Used by most GP2.1.1 cards / Oberthur OP201 cards. Visa Proprietary Card Manager AID for OpenPlatform cards (visa.openplatform).", "Country": "United States", "AID": "A000000003000000", "Type": "GP", "Name": "(VISA) Card Manager"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A00000000300037561", "Type": "", "Name": "Bonuscard"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A00000000305076010", "Type": "EMV", "Name": "VISA ELO Credit"}, {"Vendor": "Visa International", "Description": "Standard/Gold VISA credit card", "Country": "United States", "AID": "A0000000031010", "Type": "EMV", "Name": "VISA Debit/Credit (Classic)"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003101001", "Type": "EMV", "Name": "VISA Credit"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003101002", "Type": "EMV", "Name": "VISA Debit"}, {"Vendor": "Visa International", "Description": "VISA Electron (Debit)", "Country": "United States", "AID": "A0000000032010", "Type": "EMV", "Name": "VISA Electron"}, {"Vendor": "Visa International", "Description": "V PAY", "Country": "United States", "AID": "A0000000032020", "Type": "EMV", "Name": "VISA"}, {"Vendor": "Visa International", "Description": "VISA Interlink", "Country": "United States", "AID": "A0000000033010", "Type": "EMV", "Name": "VISA Interlink"}, {"Vendor": "Visa International", "Description": "Visa Specific", "Country": "United States", "AID": "A0000000034010", "Type": "EMV", "Name": "VISA Specific"}, {"Vendor": "Visa International", "Description": "Visa Specific", "Country": "United States", "AID": "A0000000035010", "Type": "EMV", "Name": "VISA Specific"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003534441", "Type": "GP", "Name": "Schlumberger Security Domain"}, {"Vendor": "Visa International", "Description": "OCS Oberthur Card System Security Domain Package AID / VGP Card Manager (for ISD and ASD)", "Country": "United States", "AID": "A0000000035350", "Type": "GP", "Name": "Security Domain"}, {"Vendor": "Visa International", "Description": "OCS Oberthur Card System Security Domain Applet AID / VGP Card Manager (for ISD and ASD)", "Country": "United States", "AID": "A000000003535041", "Type": "GP", "Name": "Security Domain"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000036010", "Type": "EMV", "Name": "Domestic Visa Cash Stored Value"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000036020", "Type": "EMV", "Name": "International Visa Cash Stored Value"}, {"Vendor": "Visa International", "Description": "VISA Auth dynamic passcode authentication (DPA). Used by Barclays/HBOS", "Country": "United States", "AID": "A0000000038002", "Type": "EMV", "Name": "VISA Auth, VisaRemAuthen EMV-CAP (DPA)"}, {"Vendor": "Visa International", "Description": "VISA plus", "Country": "United States", "AID": "A0000000038010", "Type": "EMV", "Name": "VISA Plus"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A0000000039010", "Type": "EMV", "Name": "VISA Loyalty"}, {"Vendor": "Visa International", "Description": "", "Country": "United States", "AID": "A000000003999910", "Type": "EMV", "Name": "VISA Proprietary ATM"}, {"Vendor": "Mastercard International", "Description": "Security Domain", "Country": "United States", "AID": "A0000000040000", "Type": "GP", "Name": "MasterCard Card Manager"}, {"Vendor": "Mastercard International", "Description": "AEPM (Association Europenne Payez Mobile)", "Country": "United States", "AID": "A00000000401", "Type": "EMV", "Name": "MasterCard PayPass"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A0000000041010", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A00000000410101213", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Standard MasterCard", "Country": "United States", "AID": "A00000000410101215", "Type": "EMV", "Name": "MasterCard Credit"}, {"Vendor": "Mastercard International", "Description": "Some co-branded card?", "Country": "United States", "AID": "A0000000041010BB5449435301", "Type": "", "Name": "[UNKNOWN]"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000042010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard U.S. Maestro", "Country": "United States", "AID": "A0000000042203", "Type": "", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000043010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "Maestro (Debit) Card", "Country": "United States", "AID": "A0000000043060", "Type": "EMV", "Name": "Maestro (Debit)"}, {"Vendor": "Mastercard International", "Description": "Maestro (Debit) Card", "Country": "United States", "AID": "A000000004306001", "Type": "EMV", "Name": "Maestro (Debit)"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000044010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "MasterCard Specific", "Country": "United States", "AID": "A0000000045010", "Type": "EMV", "Name": "MasterCard Specific"}, {"Vendor": "Mastercard International", "Description": "AID on Cirrus Test Card", "Country": "United States", "AID": "A0000000045555", "Type": "", "Name": "APDULogger"}, {"Vendor": "Mastercard International", "Description": "Mastercard Cirrus (Interbank Network) ATM card only", "Country": "United States", "AID": "A0000000046000", "Type": "EMV", "Name": "Cirrus"}, {"Vendor": "Mastercard International", "Description": "Chip Authentication Protocol (CAP). Works with NatWest or SecureCode Aut", "Country": "United States", "AID": "A0000000048002", "Type": "EMV", "Name": "SecureCode Auth EMV-CAP"}, {"Vendor": "Mastercard International", "Description": "", "Country": "United States", "AID": "A0000000049999", "Type": "EMV", "Name": "MasterCard PayPass??"}, {"Vendor": "Switch Card Services Ltd.", "Description": "UK Domestic Maestro - Switch (debit card)", "Country": "United Kingdom", "AID": "A0000000050001", "Type": "EMV", "Name": "Maestro UK"}, {"Vendor": "Switch Card Services Ltd.", "Description": "UK Domestic Maestro - Switch (debit card)", "Country": "United Kingdom", "AID": "A0000000050002", "Type": "EMV", "Name": "Solo"}, {"Vendor": "ETSI", "Description": "Orange UK", "Country": "France", "AID": "A0000000090001FF44FF1289", "Type": "", "Name": "Orange"}, {"Vendor": "Europay International", "Description": "", "Country": "Belgium", "AID": "A0000000101030", "Type": "", "Name": "Maestro-CH"}, {"Vendor": "GEMPLUS", "Description": "", "Country": "France", "AID": "A00000001800", "Type": "", "Name": "Gemplus ?"}, {"Vendor": "GEMPLUS", "Description": "", "Country": "France", "AID": "A0000000181001", "Type": "", "Name": "com.gemplus.javacard.util packages"}, {"Vendor": "GEMPLUS", "Description": "434D = CM (ascii). Security domain for some GCX/GXP cards (GemXpresso Pro) (Gemalto)", "Country": "France", "AID": "A000000018434D", "Type": "GP", "Name": "Gemplus card manager"}, {"Vendor": "GEMPLUS", "Description": "(Gemalto)", "Country": "France", "AID": "A000000018434D00", "Type": "GP", "Name": "Gemplus Security Domain"}, {"Vendor": "Midland Bank Plc", "Description": "", "Country": "United Kingdom", "AID": "A00000002401", "Type": "EMV", "Name": "Self Service"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "American Express (Credit/Debit)", "Country": "United Kingdom", "AID": "A0000000250000", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "AEIPS-compliant (A-E contact EMV) payment application", "Country": "United Kingdom", "AID": "A00000002501", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010104", "Type": "", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010402", "Type": "EMV", "Name": "American Express"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010701", "Type": "EMV", "Name": "ExpressPay"}, {"Vendor": "American Express", "Description": "", "Country": "United Kingdom", "AID": "A000000025010801", "Type": "EMV", "Name": "American Express"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "Link (UK) ATM Network, or AMEX (Portugal?)", "Country": "United Kingdom", "AID": "A0000000291010", "Type": "EMV", "Name": "Link / American Express"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002945087510100000", "Type": "", "Name": "CO-OP"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002949034010100001", "Type": "", "Name": "HSBC"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A00000002949282010100000", "Type": "", "Name": "Barclay"}, {"Vendor": "LINK Interchange Network Ltd", "Description": "", "Country": "United Kingdom", "AID": "A000000029564182", "Type": "", "Name": "HAFX"}, {"Vendor": "Schlumberger Industries Identif d'Encarteur PR050", "Description": "Schlumberger (Gemalto) RID", "Country": "France", "AID": "A00000003029057000AD13100101FF", "Type": "", "Name": "BelPIC (Belgian Personal Identity Card) JavaCard Applet"}, {"Vendor": "Schlumberger Industries Identif d'Encarteur PR050", "Description": "", "Country": "France", "AID": "A0000000308000000000280101", "Type": "", "Name": "Gemalto .NET Card AID"}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "Groupement des Cartes Bancaires (France)", "Country": "France", "AID": "A0000000421010", "Type": "EMV", "Name": "Cartes Bancaire EMV Card"}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000422010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000423010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000424010", "Type": "EMV", "Name": ""}, {"Vendor": "Groupement des Cartes Bancaires \"CB\"", "Description": "", "Country": "France", "AID": "A0000000425010", "Type": "EMV", "Name": ""}, {"Vendor": "Zentraler Kreditausschuss (ZKA)", "Description": "", "Country": "Germany", "AID": "A00000005945430100", "Type": "", "Name": "Girocard Electronic Cash"}, {"Vendor": "RSA Laboratories", "Description": "RSA PKCS-15 PKI application (Predecessor to ISO7816-15) / ID-card in Finland", "Country": "United States", "AID": "A000000063504B43532D3135", "Type": "", "Name": "PKCS-15"}, {"Vendor": "RSA Laboratories", "Description": "WAP (Wireless Application Protocol) Identity Module / Wireless Identification Module", "Country": "United States", "AID": "A0000000635741502D57494D", "Type": "", "Name": "WAP-WIM"}, {"Vendor": "JCB CO., LTD.", "Description": "Japan Credit Bureau", "Country": "Japan", "AID": "A00000006510", "Type": "EMV", "Name": "JCB"}, {"Vendor": "JCB CO., LTD.", "Description": "Japan Credit Bureau", "Country": "Japan", "AID": "A0000000651010", "Type": "EMV", "Name": "JCB J Smart Credit"}, {"Vendor": "Socit Europenne de Monnaie Electronique SEME", "Description": "", "Country": "France", "AID": "A00000006900", "Type": "EMV", "Name": "Moneo"}, {"Vendor": "Oberthur Technologies", "Description": "", "Country": "France", "AID": "A000000077010000021000000000003B", "Type": "EMV", "Name": "Visa AEPN"}, {"Vendor": "Activcard Europe S.A.", "Description": "Identity Key", "Country": "France", "AID": "A0000000790100", "Type": "", "Name": "CACv2 PKI ID"}, {"Vendor": "Activcard Europe S.A.", "Description": "Digital Signature Key", "Country": "France", "AID": "A0000000790101", "Type": "", "Name": "CACv2 PKI Sign"}, {"Vendor": "Activcard Europe S.A.", "Description": "Key Management Key", "Country": "France", "AID": "A0000000790102", "Type": "", "Name": "CACv2 PKI Enc"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 PKI Identity key", "Country": "France", "AID": "A00000007901F0", "Type": "", "Name": "CACv1 PKI Identity Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 Digital Signature key", "Country": "France", "AID": "A00000007901F1", "Type": "", "Name": "CACv1 PKI Digital Signature Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "Re-directs to CACv2 Key Management key", "Country": "France", "AID": "A00000007901F2", "Type": "", "Name": "CACv1 PKI Key Management Key"}, {"Vendor": "Activcard Europe S.A.", "Description": "DoD Demographic", "Country": "France", "AID": "A0000000790200", "Type": "", "Name": "CACv2 DoD Person"}, {"Vendor": "Activcard Europe S.A.", "Description": "DoD Demographic", "Country": "France", "AID": "A0000000790201", "Type": "", "Name": "CACv2 DoD Personnel"}, {"Vendor": "Activcard Europe S.A.", "Description": "General Configuration", "Country": "France", "AID": "A00000007902FB", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "PKI Certificate Attributes", "Country": "France", "AID": "A00000007902FD", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "PKI Cert", "Country": "France", "AID": "A00000007902FE", "Type": "", "Name": "CACv1 BC"}, {"Vendor": "Activcard Europe S.A.", "Description": "CAC PIN / ID PIN Management Applet", "Country": "France", "AID": "A0000000790300", "Type": "", "Name": "CACv2 Access Control Applet"}, {"Vendor": "Activcard Europe S.A.", "Description": "Joint Data Model. BCAdmin", "Country": "France", "AID": "A0000000791201", "Type": "", "Name": "CAC JDM"}, {"Vendor": "Activcard Europe S.A.", "Description": "Joint Data Model. BCMedical", "Country": "France", "AID": "A0000000791202", "Type": "", "Name": "CAC JDM"}, {"Vendor": "Third Generation Partnership Project (3GPP)", "Description": "", "Country": "France", "AID": "A0000000871002FF49FF0589", "Type": "USIM", "Name": "Telenor USIM"}, {"Vendor": "Buypass AS", "Description": "Used by norwegian public betting company Norsk-Tipping?", "Country": "Norway", "AID": "A00000008810200105C100", "Type": "BuyPass", "Name": "BuyPass BIDA"}, {"Vendor": "Buypass AS", "Description": "", "Country": "Norway", "AID": "A000000088102201034221", "Type": "BuyPass", "Name": "BuyPass BEID (BuyPass Electronic ID?)"}, {"Vendor": "Buypass AS", "Description": "", "Country": "Norway", "AID": "A000000088102201034321", "Type": "BuyPass", "Name": "BuyPass BEID (BuyPass Electronic ID?)"}, {"Vendor": "Sa Proton World International N.V.", "Description": "Proton, which is owned in part by Visa International and American Express Co., is in three other European countries: the original Proton program in Belgium, Chipknip in the Netherlands, and Cash in Switzerland", "Country": "Belgium", "AID": "A0000000960200", "Type": "GP", "Name": "Proton World International Security Domain"}, {"Vendor": "Visa USA", "Description": "Bank of America Debit Card", "Country": "United States", "AID": "A000000098", "Type": "EMV", "Name": "Debit Card"}, {"Vendor": "Visa USA", "Description": "", "Country": "United States", "AID": "A0000000980840", "Type": "", "Name": "Visa Common Debit"}, {"Vendor": "Visa USA", "Description": "Schwab Bank Debit Card", "Country": "United States", "AID": "A0000000980848", "Type": "EMV", "Name": "Debit Card"}, {"Vendor": "Die Post Postfinance", "Description": "", "Country": "Switzerland", "AID": "A0000001110101", "Type": "", "Name": "Postcard"}, {"Vendor": "GSA - TFCS", "Description": "CHUID", "Country": "United States", "AID": "A0000001160300", "Type": "", "Name": "PIV CHUID"}, {"Vendor": "GSA - TFCS", "Description": "Fingerprints", "Country": "United States", "AID": "A0000001166010", "Type": "", "Name": "PIV Fingerprints"}, {"Vendor": "GSA - TFCS", "Description": "Facial Image", "Country": "United States", "AID": "A0000001166030", "Type": "", "Name": "PIV Facial Image"}, {"Vendor": "GSA - TFCS", "Description": "Security Object", "Country": "United States", "AID": "A0000001169000", "Type": "", "Name": "PIV Security Object"}, {"Vendor": "GSA - TFCS", "Description": "PIV Authentication Key", "Country": "United States", "AID": "A000000116A001", "Type": "", "Name": "PIV Authentication Key"}, {"Vendor": "GSA - TFCS", "Description": "Card Capability Container", "Country": "United States", "AID": "A000000116DB00", "Type": "", "Name": "CCC"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118010000", "Type": "", "Name": "DF_Verkehr"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118020000", "Type": "", "Name": "DF_Partner"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "A000000118030000", "Type": "", "Name": "DF_Schlerdaten"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.32)", "Country": "Austria", "AID": "A000000118040000", "Type": "", "Name": "DF_KEP_SIG"}, {"Vendor": "Austria Card", "Description": "Digital Signature Application", "Country": "Austria", "AID": "A0000001184543", "Type": "", "Name": "Digital Signature (SSCA)"}, {"Vendor": "Austria Card", "Description": "Encryption Application (Version 1.10)", "Country": "Austria", "AID": "A000000118454E", "Type": "", "Name": "Encryption Application"}, {"Vendor": "PBS Danmark A/S", "Description": "Danish domestic debit card", "Country": "Denmark", "AID": "A0000001211010", "Type": "EMV", "Name": "Dankort (VISA GEM Vision)"}, {"Vendor": "Java Card Forum", "Description": "", "Country": "United States", "AID": "A0000001320001", "Type": "", "Name": "org.javacardforum.javacard.biometry"}, {"Vendor": "TDS TODOS DATA SYSTEM AB", "Description": "", "Country": "Sweden", "AID": "A0000001408001", "Type": "", "Name": "eCode"}, {"Vendor": "Associazione Bancaria Italiana", "Description": "CoGeBan Consorzio BANCOMAT (Italian domestic debit card)", "Country": "Italy", "AID": "A0000001410001", "Type": "EMV", "Name": "PagoBANCOMAT"}, {"Vendor": "GlobalPlatform, Inc.", "Description": "GP Card Manager", "Country": "United States", "AID": "A0000001510000", "Type": "GP", "Name": "Global Platform Security Domain AID"}, {"Vendor": "GlobalPlatform, Inc.", "Description": "SPCASD", "Country": "United States", "AID": "A00000015153504341534400", "Type": "GP", "Name": "CASD_AID"}, {"Vendor": "Diners Club International Ltd.", "Description": "Discover Card", "Country": "United States", "AID": "A0000001523010", "Type": "EMV", "Name": "Discover, Pulse D Pas"}, {"Vendor": "Diners Club International Ltd.", "Description": "Discover Debit Common Card", "Country": "United States", "AID": "A0000001524010", "Type": "EMV", "Name": "Discover"}, {"Vendor": "Banrisul - Banco do Estado do Rio Grande do SUL - S.A.", "Description": "Banrisul (Brazil)", "Country": "Brazil", "AID": "A0000001544442", "Type": "EMV", "Name": "Banricompras Debito"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570010", "Type": "", "Name": "AMEX"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570020", "Type": "", "Name": "MasterCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570021", "Type": "", "Name": "Maestro"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570022", "Type": "", "Name": "Maestro"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570023", "Type": "", "Name": "CASH"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570030", "Type": "", "Name": "VISA"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570031", "Type": "", "Name": "VISA"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570040", "Type": "", "Name": "JCB"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570050", "Type": "", "Name": "Postcard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570051", "Type": "", "Name": "Postcard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570100", "Type": "", "Name": "MCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570104", "Type": "", "Name": "MyOne"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001570109", "Type": "", "Name": "Mediamarkt Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010A", "Type": "", "Name": "Gift Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010B", "Type": "", "Name": "Bonuscard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010C", "Type": "", "Name": "WIRCard"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A000000157010D", "Type": "", "Name": "Power Card"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001574443", "Type": "", "Name": "DINERS CLUB"}, {"Vendor": "Zhlke Engineering AG", "Description": "", "Country": "Switzerland", "AID": "A0000001574444", "Type": "", "Name": "Supercard Plus"}, {"Vendor": "IBM", "Description": "identify in JCOP-tools returns eg 27 34 01 2E 00 00 00 00 4E 58 37 35 31 41 00 03 28 62 B3 6A 82", "Country": "Germany", "AID": "A000000167413000FF", "Type": "JCOP", "Name": "JCOP Identify Applet"}, {"Vendor": "IBM", "Description": "?", "Country": "Germany", "AID": "A000000167413001", "Type": "", "Name": "FIPS 140-2"}, {"Vendor": "Financial Information Service Co. Ltd.", "Description": "The Bankers Association of the Republic of China", "Country": "Taiwan", "AID": "A000000172950001", "Type": "EMV", "Name": "BAROC Financial Application Taiwan"}, {"Vendor": "Ministre de L'Intrieur", "Description": "", "Country": "Belgium", "AID": "A000000177504B43532D3135", "Type": "", "Name": "BelPIC (Belgian Personal Identity Card)"}, {"Vendor": "Post Office Limited", "Description": "", "Country": "United Kingdom", "AID": "A0000001850002", "Type": "EMV", "Name": "UK Post Office Account card"}, {"Vendor": "Diners Club Switzerland Ltd", "Description": "", "Country": "Switzerland", "AID": "A0000001884443", "Type": "", "Name": "DINERS CLUB"}, {"Vendor": "Association for Payment Clearing Services", "Description": "", "Country": "United Kingdom", "AID": "A0000002040000", "Type": "", "Name": "?"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A0000002281010", "Type": "EMV", "Name": "SPAN (M/Chip)"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A0000002282010", "Type": "EMV", "Name": "SPAN (VIS)"}, {"Vendor": "Saudi Arabian Monetary Agency (SAMA)", "Description": "SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency)", "Country": "Kingdom of Saudi Arabia", "AID": "A00000022820101010", "Type": "", "Name": "SPAN"}, {"Vendor": "ISO JTC1/SC17/WG3", "Description": "Electronic (Biometric) Passport. Issuer stored data application (The last three digits of the PIX shall be used to denote future version levels.)", "Country": "United Kingdom", "AID": "A0000002471001", "Type": "MRTD", "Name": "Machine Readable Travel Documents (MRTD)"}, {"Vendor": "ISO JTC1/SC17/WG3", "Description": "Electronic (Biometric) Passport. Application for hashes, digital signature, and certificate (The last three digits of the PIX shall be used to denote future version levels.)", "Country": "United Kingdom", "AID": "A0000002472001", "Type": "MRTD", "Name": "Machine Readable Travel Documents (MRTD)"}, {"Vendor": "Interac Association", "Description": "Canadian domestic credit/debit card", "Country": "Canada", "AID": "A0000002771010", "Type": "EMV", "Name": "INTERAC"}, {"Vendor": "PS/SC Workgroup", "Description": "Possibly not an application...", "Country": "United States", "AID": "A00000030600000000000000", "Type": "", "Name": "PC/SC Initial access data AID"}, {"Vendor": "National Institute of Standards and Technology", "Description": "PIV End Point Applet. Last 2 bytes designate version?", "Country": "United States", "AID": "A000000308000010000100", "Type": "", "Name": "Personal Identity Verification (PIV) / ID-ONE PIV BIO"}, {"Vendor": "Currence Holding/PIN BV", "Description": "", "Country": "The Netherlands", "AID": "A00000031510100528", "Type": "EMV", "Name": "Currence PuC"}, {"Vendor": "Currence Holding/PIN BV", "Description": "", "Country": "The Netherlands", "AID": "A0000003156020", "Type": "EMV", "Name": "Chipknip"}, {"Vendor": "Identity Alliance", "Description": "http://osdir.com/ml/lib.muscle/2005-12/msg00066.html", "Country": "United States", "AID": "A00000032301", "Type": "", "Name": "MUSCLE Applet Package"}, {"Vendor": "Identity Alliance", "Description": "http://osdir.com/ml/lib.muscle/2005-12/msg00066.html", "Country": "United States", "AID": "A0000003230101", "Type": "", "Name": "MUSCLE Applet Instance"}, {"Vendor": "Discover Financial Services LLC", "Description": "", "Country": "United States", "AID": "A0000003241010", "Type": "", "Name": "Discover Expresspay (ZIP)"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010101", "Type": "", "Name": "UnionPay Debit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010102", "Type": "", "Name": "UnionPay Credit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010103", "Type": "", "Name": "UnionPay Quasi Credit"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010106", "Type": "", "Name": "UnionPay Electronic Cash"}, {"Vendor": "China Unionpay Co. Ltd", "Description": "", "Country": "China", "AID": "A000000333010108", "Type": "", "Name": "U.S. UnionPay Common Debit AID"}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "Unknown", "Country": "Belgium", "AID": "A0000003591010", "Type": "", "Name": ""}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "ZKA (Germany)", "Country": "Belgium", "AID": "A0000003591010028001", "Type": "EMV", "Name": "Girocard EAPS"}, {"Vendor": "Euro Alliance of Payment Schemes s.c.r.l. - EAPS", "Description": "PagoBANCOMAT", "Country": "Belgium", "AID": "A00000035910100380", "Type": "", "Name": ""}, {"Vendor": "Poste Italiane S.P.A", "Description": "", "Country": "Italy", "AID": "A0000003660001", "Type": "", "Name": "Postamat"}, {"Vendor": "Poste Italiane S.P.A", "Description": "", "Country": "Italy", "AID": "A0000003660002", "Type": "", "Name": "Postamat VISA"}, {"Vendor": "Interswitch Limited", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000003710001", "Type": "EMV", "Name": "InterSwitch Verve Card"}, {"Vendor": "NXP Semiconductors Germany GmbH", "Description": "NXP Mf4M", "Country": "Germany", "AID": "A0000003964D66344D0002", "Type": "", "Name": "MIFARE4MOBILE"}, {"Vendor": "Microsoft Corporation", "Description": "Identity Device With Microsoft Generic Profile application. 2 bytes can be added at the end. This byte must be set to the IDMP specification revision number which is currently 0x01. The second byte (yy) is reserved for use by the card application.", "Country": "United States", "AID": "A00000039742544659", "Type": "", "Name": "Microsoft IDMP AID"}, {"Vendor": "Microsoft Corporation", "Description": "MS Plug and Play", "Country": "United States", "AID": "A0000003974349445F0100", "Type": "", "Name": "Microsoft PNP AID"}, {"Vendor": "Unibanco (Hipercard)", "Description": "", "Country": "Brazil", "AID": "A0000004271010", "Type": "", "Name": "Hiperchip"}, {"Vendor": "100", "Description": "", "Country": "Russia", "AID": "A0000004320001", "Type": "", "Name": "Universal Electronic Card"}, {"Vendor": "Edenred", "Description": "", "Country": "Belgium", "AID": "A0000004360100", "Type": "", "Name": "Ticket Restaurant"}, {"Vendor": "ACCEL/Exchange", "Description": "The Exchange Network ATM Network", "Country": "United States", "AID": "A0000004391010", "Type": "", "Name": "Exchange ATM card"}, {"Vendor": "eTranzact", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000004540010", "Type": "EMV", "Name": "Etranzact Genesis Card"}, {"Vendor": "eTranzact", "Description": "Nigerian local switch company", "Country": "Nigeria", "AID": "A0000004540011", "Type": "EMV", "Name": "Etranzact Genesis Card 2"}, {"Vendor": "Google", "Description": "GOOGLE_LOCKET_AID", "Country": "United States", "AID": "A0000004762010", "Type": "", "Name": "GOOGLE_CONTROLLER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A0000004763030", "Type": "", "Name": "GOOGLE_MIFARE_MANAGER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A0000004766C", "Type": "EMV", "Name": "GOOGLE_PAYMENT_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A000000476A010", "Type": "GP", "Name": "GSD_MANAGER_AID"}, {"Vendor": "Google", "Description": "", "Country": "United States", "AID": "A000000476A110", "Type": "GP", "Name": "GSD_MANAGER_AID"}, {"Vendor": "JVL Ventures, LLC (Softcard)", "Description": "", "Country": "United States", "AID": "A000000485", "Type": "", "Name": "Softcard SmartTap"}, {"Vendor": "RuPay", "Description": "RuPay (India)", "Country": "India", "AID": "A0000005241010", "Type": "EMV", "Name": "RuPay"}, {"Vendor": "Yubico", "Description": "Universal 2-Factor Proof-of-concept/Demo", "Country": "Sweden", "AID": "A0000005271002", "Type": "YKNEO", "Name": "Yubikey NEO U2F Demo applet"}, {"Vendor": "Yubico", "Description": "Javacard Applet AID", "Country": "Sweden", "AID": "A000000527200101", "Type": "YKNEO", "Name": "Yubikey NEO Yubikey2 applet interface"}, {"Vendor": "Yubico", "Description": "Javacard Applet AID", "Country": "Sweden", "AID": "A000000527210101", "Type": "YKNEO", "Name": "Yubikey NEO OATH Applet"}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000100", "Type": "", "Name": "ISD-R Application. Used as TAR."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000200", "Type": "", "Name": "ECASD Application. Used as TAR."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000D00", "Type": "", "Name": "ISD-P Executable Load File."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000E00", "Type": "", "Name": "ISD-P Executable Module."}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900000F00", "Type": "", "Name": "Reserved value for the Profile's ISD-P"}, {"Vendor": "GSMA (GSM Association)", "Description": "", "Country": "United Kingdom", "AID": "A0000005591010FFFFFFFF8900001000", "Type": "", "Name": "ISD-P Application ('1010FFFFFFFF89000010' to '1010FFFFFFFF8900FFFF'. Used as TAR. The value is allocated during the 'Profile Download and Installation procedure'"}, {"Vendor": "Fidesmo", "Description": "", "Country": "Sweden", "AID": "A00000061700", "Type": "", "Name": "Fidesmo javacard"}, {"Vendor": "Debit Network Alliance (DNA)", "Description": "Common U.S. Debit", "Country": "United States", "AID": "A0000006200620", "Type": "", "Name": "Debit Network Alliance (DNA)"}, {"Vendor": "MIR", "Description": "", "Country": "Russia", "AID": "A0000006581010", "Type": "", "Name": "MIR Credit"}, {"Vendor": "MIR", "Description": "", "Country": "Russia", "AID": "A0000006582010", "Type": "", "Name": "MIR Debit"}, {"Vendor": "TROY", "Description": "Turkey's Payment Method", "Country": "Turkey", "AID": "A0000006723010", "Type": "EMV", "Name": "TROY chip credit card"}, {"Vendor": "TROY", "Description": "Turkey's Payment Method", "Country": "Turkey", "AID": "A0000006723020", "Type": "EMV", "Name": "TROY chip debit card"}, {"Vendor": "Indian Oil Corporation Limited", "Description": "Indian Oils Pre Paid Program", "Country": "India", "AID": "A0000007705850", "Type": "EMV", "Name": "XTRAPOWER Fleet Card Program"}, {"Vendor": "MasterCard International", "Description": "Used for development", "Country": "United States", "AID": "B012345678", "Type": "EMV", "Name": "Maestro TEST"}, {"Vendor": "Paylife", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000001000002", "Type": "", "Name": "Paylife Quick (IEP). Preloaded Electronic Purse"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000002000002", "Type": "", "Name": "RFU"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000003000002", "Type": "", "Name": "POS"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D040000004000002", "Type": "", "Name": "ATM"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000B000002", "Type": "", "Name": "Retail"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000C000002", "Type": "", "Name": "Bank_Data"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.1)", "Country": "Austria", "AID": "D04000000D000002", "Type": "", "Name": "Shopping"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000013000001", "Type": "", "Name": "DF_UNI_Kepler1"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000013000001", "Type": "", "Name": "DF_Schler1"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000013000002", "Type": "", "Name": "DF_UNI_Kepler2"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000013000002", "Type": "", "Name": "DF_Schler2"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000014000001", "Type": "", "Name": "DF_Mensa"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 2.0)", "Country": "Austria", "AID": "D040000015000001", "Type": "", "Name": "DF_UNI_Ausweis"}, {"Vendor": "Austria Card", "Description": "Domestic Loyalty Program (Version 1.3)", "Country": "Austria", "AID": "D040000015000001", "Type": "", "Name": "DF_Ausweis"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190001", "Type": "", "Name": "EMV ATM Maestro"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190002", "Type": "", "Name": "EMV POS Maestro"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190003", "Type": "", "Name": "EMV ATM MasterCard"}, {"Vendor": "Austria Card", "Description": "Domestic EMV Application (Version 2.1)", "Country": "Austria", "AID": "D0400000190004", "Type": "", "Name": "EMV POS MasterCard"}, {"Vendor": "Austria Card", "Description": "Domestic Payment System (Version 2.1)", "Country": "Austria", "AID": "D0400000190010", "Type": "", "Name": "Digital ID"}, {"Vendor": "Ministry of Finance of Georgia", "Description": "Georgia Revenue Service application for fiscal cash registers", "Country": "Georgia", "AID": "D268000001", "Type": "", "Name": "Fiscal module application"}, {"Vendor": "Giesecke&Devrient", "Description": "Giesecke & Devrient", "Country": "Germany", "AID": "D276000005", "Type": "", "Name": ""}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA040360010410", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E00401", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E00501", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AA0503E0050101", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "Giesecke&Devrient", "Description": "", "Country": "Germany", "AID": "D276000005AB0503E0040101", "Type": "", "Name": "G D App Nokia 6212"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000001", "Type": "", "Name": "SCT LOYALTY"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000002", "Type": "", "Name": "BUSINESS CARD"}, {"Vendor": "IBM Laboratories", "Description": "IBM Test card from the book 'Smart Card Application Development Using Java'", "Country": "Germany", "AID": "D27600002200000060", "Type": "", "Name": "PKCS#11 Token"}, {"Vendor": "ZKA", "Description": "Girocard (Geldkarte) in Germany", "Country": "Germany", "AID": "D276000025", "Type": "", "Name": "Girocard"}, {"Vendor": "ZKA", "Description": "Unknown", "Country": "Germany", "AID": "D27600002545410100", "Type": "", "Name": ""}, {"Vendor": "ZKA", "Description": "ZKA Girocard (Geldkarte) (Germany)", "Country": "Germany", "AID": "D27600002545500100", "Type": "EMV", "Name": "Girocard"}, {"Vendor": "ZKA", "Description": "", "Country": "Germany", "AID": "D27600002547410100", "Type": "", "Name": "Girocard ATM"}, {"Vendor": "Wolfgang Rankl", "Description": "", "Country": "Germany", "AID": "D276000060", "Type": "", "Name": ""}, {"Vendor": "NXP Semiconductors / NFC Forum", "Description": "NFC Forum Type 4 Tag", "Country": "Germany", "AID": "D2760000850100", "Type": "", "Name": "NDEF Tag Application / Mifare DESFire Tag Application"}, {"Vendor": "NXP Semiconductors / NFC Forum", "Description": "NFC Tag type 4 tag", "Country": "Germany", "AID": "D2760000850101", "Type": "", "Name": "NDEF Tag Application"}, {"Vendor": "Giesecke&Devrient Java Card Telecommunikation", "Description": "", "Country": "Germany", "AID": "D276000118", "Type": "", "Name": ""}, {"Vendor": "Giesecke&Devrient Java Card Telecommunikation", "Description": "Devrient Test Applet?", "Country": "Germany", "AID": "D2760001180101", "Type": "", "Name": "Giesecke &"}, {"Vendor": "fsfEurope", "Description": "For selection when not knowing the exact full AID", "Country": "Germany", "AID": "D27600012401", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "Version 1", "Country": "Germany", "AID": "D276000124010101FFFF000000010000", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "Version 2", "Country": "Germany", "AID": "D2760001240102000000000000010000", "Type": "OpenPGP", "Name": "OpenPGP Card"}, {"Vendor": "fsfEurope", "Description": "http://smartchess.de/englisch/SmartChess_1.0.pdf", "Country": "Germany", "AID": "D27600012402", "Type": "SmartChess", "Name": "SmartChess"}, {"Vendor": "fsfEurope", "Description": "http://smartchess.de/englisch/SmartChess_1.0.pdf", "Country": "Germany", "AID": "D2760001240200010000000000000000", "Type": "SmartChess", "Name": "SmartChess"}, {"Vendor": "", "Description": "", "Country": "Republic of Korea", "AID": "D4100000011010", "Type": "", "Name": ""}, {"Vendor": "", "Description": "(Netherlands)", "Country": "The Netherlands", "AID": "D5280050218002", "Type": "EMV", "Name": "?"}, {"Vendor": "Bankaxept", "Description": "Norwegian domestic debit card", "Country": "Norway", "AID": "D5780000021010", "Type": "EMV", "Name": "Bankaxept"}, {"Vendor": "Swiss Travel Fund (Reka)", "Description": "prepaid functional debit card", "Country": "Switzerland", "AID": "D7560000010101", "Type": "", "Name": "Reka Card"}, {"Vendor": "Migros (FCM, GE Money Bank and MasterCard)", "Description": "", "Country": "Switzerland", "AID": "D7560000300101", "Type": "", "Name": "M Budget"}, {"Vendor": "", "Description": "German eID", "Country": "", "AID": "E80704007F00070302", "Type": "", "Name": "nPA"}, {"Vendor": "", "Description": "", "Country": "", "AID": "E82881C11702", "Type": "", "Name": "AlphaCard application"}, {"Vendor": "", "Description": "Iso adoption of PKCS-15", "Country": "", "AID": "E828BD080F", "Type": "", "Name": "ISO-7816-15 EF.DIR"}, {"Vendor": "", "Description": "Brazilian Bank Banco Bradesco", "Country": "", "AID": "F0000000030001", "Type": "EMV", "Name": "BRADESCO"}] \ No newline at end of file diff --git a/client/amiitool/LICENSE b/client/amiitool/LICENSE new file mode 100644 index 000000000..35627b40f --- /dev/null +++ b/client/amiitool/LICENSE @@ -0,0 +1,21 @@ +(c) 2015-2017 Marcos Del Sol Vives +(c) 2016 javiMaD +(c) 2016 Michael Armbruster + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/client/amiitool/amiibo.c b/client/amiitool/amiibo.c new file mode 100644 index 000000000..a8596e30a --- /dev/null +++ b/client/amiitool/amiibo.c @@ -0,0 +1,180 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include "amiibo.h" +#include "mbedtls/md.h" +#include "mbedtls/aes.h" + +#define HMAC_POS_DATA 0x008 +#define HMAC_POS_TAG 0x1B4 + +void nfc3d_amiibo_calc_seed(const uint8_t *dump, uint8_t *key) { + memcpy(key + 0x00, dump + 0x029, 0x02); + memset(key + 0x02, 0x00, 0x0E); + memcpy(key + 0x10, dump + 0x1D4, 0x08); + memcpy(key + 0x18, dump + 0x1D4, 0x08); + memcpy(key + 0x20, dump + 0x1E8, 0x20); +} + +void nfc3d_amiibo_keygen(const nfc3d_keygen_masterkeys *masterKeys, const uint8_t *dump, nfc3d_keygen_derivedkeys *derivedKeys) { + uint8_t seed[NFC3D_KEYGEN_SEED_SIZE]; + + nfc3d_amiibo_calc_seed(dump, seed); + nfc3d_keygen(masterKeys, seed, derivedKeys); +} + +void nfc3d_amiibo_cipher(const nfc3d_keygen_derivedkeys *keys, const uint8_t *in, uint8_t *out) { + mbedtls_aes_context aes; + size_t nc_off = 0; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; + + mbedtls_aes_setkey_enc(&aes, keys->aesKey, 128); + memset(nonce_counter, 0, sizeof(nonce_counter)); + memset(stream_block, 0, sizeof(stream_block)); + memcpy(nonce_counter, keys->aesIV, sizeof(nonce_counter)); + mbedtls_aes_crypt_ctr(&aes, 0x188, &nc_off, nonce_counter, stream_block, in + 0x02C, out + 0x02C); + + memcpy(out + 0x000, in + 0x000, 0x008); + // Data signature NOT copied + memcpy(out + 0x028, in + 0x028, 0x004); + // Tag signature NOT copied + memcpy(out + 0x1D4, in + 0x1D4, 0x034); +} + +void nfc3d_amiibo_tag_to_internal(const uint8_t *tag, uint8_t *intl) { + memcpy(intl + 0x000, tag + 0x008, 0x008); + memcpy(intl + 0x008, tag + 0x080, 0x020); + memcpy(intl + 0x028, tag + 0x010, 0x024); + memcpy(intl + 0x04C, tag + 0x0A0, 0x168); + memcpy(intl + 0x1B4, tag + 0x034, 0x020); + memcpy(intl + 0x1D4, tag + 0x000, 0x008); + memcpy(intl + 0x1DC, tag + 0x054, 0x02C); +} + +void nfc3d_amiibo_internal_to_tag(const uint8_t *intl, uint8_t *tag) { + memcpy(tag + 0x008, intl + 0x000, 0x008); + memcpy(tag + 0x080, intl + 0x008, 0x020); + memcpy(tag + 0x010, intl + 0x028, 0x024); + memcpy(tag + 0x0A0, intl + 0x04C, 0x168); + memcpy(tag + 0x034, intl + 0x1B4, 0x020); + memcpy(tag + 0x000, intl + 0x1D4, 0x008); + memcpy(tag + 0x054, intl + 0x1DC, 0x02C); +} + +bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *tag, uint8_t *plain) { + uint8_t internal[NFC3D_AMIIBO_SIZE]; + nfc3d_keygen_derivedkeys dataKeys; + nfc3d_keygen_derivedkeys tagKeys; + + // Convert format + nfc3d_amiibo_tag_to_internal(tag, internal); + + // Generate keys + nfc3d_amiibo_keygen(&amiiboKeys->data, internal, &dataKeys); + nfc3d_amiibo_keygen(&amiiboKeys->tag, internal, &tagKeys); + + // Decrypt + nfc3d_amiibo_cipher(&dataKeys, internal, plain); + + // Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC! + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey), + plain + 0x1D4, 0x34, plain + HMAC_POS_TAG); + + // Regenerate data HMAC + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), dataKeys.hmacKey, sizeof(dataKeys.hmacKey), + plain + 0x029, 0x1DF, plain + HMAC_POS_DATA); + + return + memcmp(plain + HMAC_POS_DATA, internal + HMAC_POS_DATA, 32) == 0 && + memcmp(plain + HMAC_POS_TAG, internal + HMAC_POS_TAG, 32) == 0; +} + +void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain, uint8_t *tag) { + uint8_t cipher[NFC3D_AMIIBO_SIZE]; + nfc3d_keygen_derivedkeys tagKeys; + nfc3d_keygen_derivedkeys dataKeys; + + // Generate keys + nfc3d_amiibo_keygen(&amiiboKeys->tag, plain, &tagKeys); + nfc3d_amiibo_keygen(&amiiboKeys->data, plain, &dataKeys); + + // Generate tag HMAC + mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tagKeys.hmacKey, sizeof(tagKeys.hmacKey), + plain + 0x1D4, 0x34, cipher + HMAC_POS_TAG); + + // Init mbedtls HMAC context + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); + + // Generate data HMAC + mbedtls_md_hmac_starts(&ctx, dataKeys.hmacKey, sizeof(dataKeys.hmacKey)); + mbedtls_md_hmac_update(&ctx, plain + 0x029, 0x18B); // Data + mbedtls_md_hmac_update(&ctx, cipher + HMAC_POS_TAG, 0x20); // Tag HMAC + mbedtls_md_hmac_update(&ctx, plain + 0x1D4, 0x34); // Here be dragons + + mbedtls_md_hmac_finish(&ctx, cipher + HMAC_POS_DATA); + + // HMAC cleanup + mbedtls_md_free(&ctx); + + // Encrypt + nfc3d_amiibo_cipher(&dataKeys, plain, cipher); + + // Convert back to hardware + nfc3d_amiibo_internal_to_tag(cipher, tag); +} + +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path) { + FILE *f = fopen(path, "rb"); + if (!f) { + return false; + } + + if (!fread(amiiboKeys, sizeof(*amiiboKeys), 1, f)) { + fclose(f); + return false; + } + fclose(f); + + if ( + (amiiboKeys->data.magicBytesSize > 16) || + (amiiboKeys->tag.magicBytesSize > 16) + ) { + return false; + } + + return true; +} + +void nfc3d_amiibo_copy_app_data(const uint8_t *src, uint8_t *dst) { + + + //uint16_t *ami_nb_wr = (uint16_t*)(dst + 0x29); + //uint16_t *cfg_nb_wr = (uint16_t*)(dst + 0xB4); + + /* increment write counters */ + //*ami_nb_wr = htobe16(be16toh(*ami_nb_wr) + 1); + //*cfg_nb_wr = htobe16(be16toh(*cfg_nb_wr) + 1); + + uint16_t ami_nb_wr = ((uint16_t)bytes_to_num(dst + 0x29, 2)) + 1; + uint16_t cfg_nb_wr = ((uint16_t)bytes_to_num(dst + 0xB4, 2)) + 1; + + num_to_bytes(ami_nb_wr, 2, dst + 0x29); + num_to_bytes(cfg_nb_wr, 2, dst + 0xB4); + + /* copy flags */ + dst[0x2C] = src[0x2C]; + /* copy programID */ + memcpy(dst + 0xAC, src + 0xAC, 8); + /* copy AppID */ + memcpy(dst + 0xB6, src + 0xB6, 4); + /* copy AppData */ + memcpy(dst + 0xDC, src + 0xDC, 216); +} + diff --git a/client/amiitool/amiibo.h b/client/amiitool/amiibo.h new file mode 100644 index 000000000..7b56a2c0a --- /dev/null +++ b/client/amiitool/amiibo.h @@ -0,0 +1,32 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_AMIIBO_H +#define HAVE_NFC3D_AMIIBO_H + +#include +#include +#include +#include +#include "keygen.h" +#include "util.h" + +#define NFC3D_AMIIBO_SIZE 520 + +#pragma pack(1) +typedef struct { + nfc3d_keygen_masterkeys data; + nfc3d_keygen_masterkeys tag; +} nfc3d_amiibo_keys; +#pragma pack() + +bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *tag, uint8_t *plain); +void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain, uint8_t *tag); +bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path); +void nfc3d_amiibo_copy_app_data(const uint8_t *src, uint8_t *dst); + +#endif diff --git a/client/amiitool/amiitool.c b/client/amiitool/amiitool.c new file mode 100644 index 000000000..78c8f4d1e --- /dev/null +++ b/client/amiitool/amiitool.c @@ -0,0 +1,175 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../loclass/fileutils.h" + +#define NTAG215_SIZE 540 + +static char *self; + +void amiitool_usage() { + fprintf(stderr, + "amiitool build %i (commit %s-%08x)\n" + "by Marcos Del Sol Vives \n" + "\n" + "Usage: %s (-e|-d|-c) -k keyfile [-i input] [-s input2] [-o output]\n" + " -e encrypt and sign amiibo\n" + " -d decrypt and test amiibo\n" + " -c decrypt, copy AppData and encrypt amiibo\n" + " -k key set file. For retail amiibo, use \"retail unfixed\" key set\n" + " -i input file. If not specified, stdin will be used.\n" + " -s input save file, save from this file will replace input file ones.\n" + " -o output file. If not specified, stdout will be used.\n" + " -l decrypt files with invalid signatures.\n", + , self + ); +} + +static bool LoadAmiikey(nfc3d_amiibo_keys keys, char *keyfile) { + + if (!nfc3d_amiibo_load_keys(&keys, keyfile)) { + PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile); + return false; + } + return true; +} + +int main(int argc, char **argv) { + self = argv[0]; + + char *infile = NULL; + char *savefile = NULL; + char *outfile = NULL; + char *keyfile = NULL; + char op = '\0'; + bool lenient = false; + + char c; + while ((c = getopt(argc, argv, "edci:s:o:k:l")) != -1) { + switch (c) { + case 'e': + case 'd': + case 'c': + op = c; + break; + case 'i': + infile = optarg; + break; + case 's': + savefile = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'l': + lenient = true; + break; + default: + amiitool_usage(); + return 2; + } + } + + if (op == '\0' || keyfile == NULL) { + amiitool_usage(); + return 1; + } + + nfc3d_amiibo_keys amiiboKeys; + + + uint8_t original[NTAG215_SIZE]; + uint8_t modified[NFC3D_AMIIBO_SIZE]; + + FILE *f = stdin; + if (infile) { + f = fopen(infile, "rb"); + if (!f) { + fprintf(stderr, "Could not open input file\n"); + return 3; + } + } + size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f); + if (readPages < NFC3D_AMIIBO_SIZE / 4) { + fprintf(stderr, "Could not read from input\n"); + fclose(f); + return 3; + } + fclose(f); + + + if (op == 'e') { + nfc3d_amiibo_pack(&amiiboKeys, original, modified); + } else if (op == 'd') { + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, modified)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + } else { /* copy */ + uint8_t plain_base[NFC3D_AMIIBO_SIZE]; + uint8_t plain_save[NFC3D_AMIIBO_SIZE]; + + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_base)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + if (savefile) { + f = fopen(savefile, "rb"); + if (!f) { + fprintf(stderr, "Could not open save file\n"); + return 3; + } + } + size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f); + if (readPages < NFC3D_AMIIBO_SIZE / 4) { + fprintf(stderr, "Could not read from save\n"); + fclose(f); + return 3; + } + fclose(f); + + if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_save)) { + fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n"); + if (!lenient) { + return 6; + } + } + + nfc3d_amiibo_copy_app_data(plain_save, plain_base); + nfc3d_amiibo_pack(&amiiboKeys, plain_base, modified); + } + + f = stdout; + if (outfile) { + f = fopen(outfile, "wb"); + if (!f) { + fprintf(stderr, "Could not open output file\n"); + return 4; + } + } + if (fwrite(modified, NFC3D_AMIIBO_SIZE, 1, f) != 1) { + fprintf(stderr, "Could not write to output\n"); + fclose(f); + return 4; + } + if (readPages > NFC3D_AMIIBO_SIZE / 4) { + if (fwrite(original + NFC3D_AMIIBO_SIZE, readPages * 4 - NFC3D_AMIIBO_SIZE, 1, f) != 1) { + fprintf(stderr, "Could not write to output:\n"); + fclose(f); + return 4; + } + } + fclose(f); + return 0; +} diff --git a/client/amiitool/drbg.c b/client/amiitool/drbg.c new file mode 100644 index 000000000..623a29776 --- /dev/null +++ b/client/amiitool/drbg.c @@ -0,0 +1,78 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#include "drbg.h" +#include +#include +#include + +void nfc3d_drbg_init(nfc3d_drbg_ctx *ctx, const uint8_t *hmacKey, size_t hmacKeySize, const uint8_t *seed, size_t seedSize) { + assert(ctx != NULL); + assert(hmacKey != NULL); + assert(seed != NULL); + assert(seedSize <= NFC3D_DRBG_MAX_SEED_SIZE); + + // Initialize primitives + ctx->used = false; + ctx->iteration = 0; + ctx->bufferSize = sizeof(ctx->iteration) + seedSize; + + // The 16-bit counter is prepended to the seed when hashing, so we'll leave 2 bytes at the start + memcpy(ctx->buffer + sizeof(uint16_t), seed, seedSize); + + // Initialize underlying HMAC context + mbedtls_md_init(&ctx->hmacCtx); + mbedtls_md_setup(&ctx->hmacCtx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1); + mbedtls_md_hmac_starts(&ctx->hmacCtx, hmacKey, hmacKeySize); +} + +void nfc3d_drbg_step(nfc3d_drbg_ctx *ctx, uint8_t *output) { + assert(ctx != NULL); + assert(output != NULL); + + if (ctx->used) { + // If used at least once, reinitialize the HMAC + mbedtls_md_hmac_reset(&ctx->hmacCtx); + } else { + ctx->used = true; + } + + // Store counter in big endian, and increment it + ctx->buffer[0] = ctx->iteration >> 8; + ctx->buffer[1] = ctx->iteration >> 0; + ctx->iteration++; + + // Do HMAC magic + mbedtls_md_hmac_update(&ctx->hmacCtx, ctx->buffer, ctx->bufferSize); + mbedtls_md_hmac_finish(&ctx->hmacCtx, output); +} + +void nfc3d_drbg_cleanup(nfc3d_drbg_ctx *ctx) { + assert(ctx != NULL); + mbedtls_md_free(&ctx->hmacCtx); +} + +void nfc3d_drbg_generate_bytes(const uint8_t *hmacKey, size_t hmacKeySize, const uint8_t *seed, size_t seedSize, uint8_t *output, size_t outputSize) { + uint8_t temp[NFC3D_DRBG_OUTPUT_SIZE]; + + nfc3d_drbg_ctx rngCtx; + nfc3d_drbg_init(&rngCtx, hmacKey, hmacKeySize, seed, seedSize); + + while (outputSize > 0) { + if (outputSize < NFC3D_DRBG_OUTPUT_SIZE) { + nfc3d_drbg_step(&rngCtx, temp); + memcpy(output, temp, outputSize); + break; + } + + nfc3d_drbg_step(&rngCtx, output); + output += NFC3D_DRBG_OUTPUT_SIZE; + outputSize -= NFC3D_DRBG_OUTPUT_SIZE; + } + + nfc3d_drbg_cleanup(&rngCtx); +} diff --git a/client/amiitool/drbg.h b/client/amiitool/drbg.h new file mode 100644 index 000000000..d77d030ac --- /dev/null +++ b/client/amiitool/drbg.h @@ -0,0 +1,33 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * (c) 2016 javiMaD + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_DRBG_H +#define HAVE_NFC3D_DRBG_H + +#include +#include +#include "mbedtls/md.h" + +#define NFC3D_DRBG_MAX_SEED_SIZE 480 /* Hardcoded max size in 3DS NFC module */ +#define NFC3D_DRBG_OUTPUT_SIZE 32 /* Every iteration generates 32 bytes */ + +typedef struct { + mbedtls_md_context_t hmacCtx; + bool used; + uint16_t iteration; + + uint8_t buffer[sizeof(uint16_t) + NFC3D_DRBG_MAX_SEED_SIZE]; + size_t bufferSize; +} nfc3d_drbg_ctx; + +void nfc3d_drbg_init(nfc3d_drbg_ctx *ctx, const uint8_t *hmacKey, size_t hmacKeySize, const uint8_t *seed, size_t seedSize); +void nfc3d_drbg_step(nfc3d_drbg_ctx *ctx, uint8_t *output); +void nfc3d_drbg_cleanup(nfc3d_drbg_ctx *ctx); +void nfc3d_drbg_generate_bytes(const uint8_t *hmacKey, size_t hmacKeySize, const uint8_t *seed, size_t seedSize, uint8_t *output, size_t outputSize); + +#endif + diff --git a/client/amiitool/key_retail.bin b/client/amiitool/key_retail.bin new file mode 100644 index 000000000..9ecc9e35a Binary files /dev/null and b/client/amiitool/key_retail.bin differ diff --git a/client/amiitool/keygen.c b/client/amiitool/keygen.c new file mode 100644 index 000000000..4b74a0232 --- /dev/null +++ b/client/amiitool/keygen.c @@ -0,0 +1,53 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * + * SPDX-License-Identifier: MIT + */ + +#include "drbg.h" +#include "keygen.h" +#include +#include +#include + +void nfc3d_keygen_prepare_seed(const nfc3d_keygen_masterkeys *baseKeys, const uint8_t *baseSeed, uint8_t *output, size_t *outputSize) { + assert(baseKeys != NULL); + assert(baseSeed != NULL); + assert(output != NULL); + assert(outputSize != NULL); + + uint8_t *start = output; + + // 1: Copy whole type string + output = memccpy(output, baseKeys->typeString, '\0', sizeof(baseKeys->typeString)); + + // 2: Append (16 - magicBytesSize) from the input seed + size_t leadingSeedBytes = 16 - baseKeys->magicBytesSize; + memcpy(output, baseSeed, leadingSeedBytes); + output += leadingSeedBytes; + + // 3: Append all bytes from magicBytes + memcpy(output, baseKeys->magicBytes, baseKeys->magicBytesSize); + output += baseKeys->magicBytesSize; + + // 4: Append bytes 0x10-0x1F from input seed + memcpy(output, baseSeed + 0x10, 16); + output += 16; + + // 5: Xor last bytes 0x20-0x3F of input seed with AES XOR pad and append them + unsigned int i; + for (i = 0; i < 32; i++) { + output[i] = baseSeed[i + 32] ^ baseKeys->xorPad[i]; + } + output += 32; + + *outputSize = output - start; +} + +void nfc3d_keygen(const nfc3d_keygen_masterkeys *baseKeys, const uint8_t *baseSeed, nfc3d_keygen_derivedkeys *derivedKeys) { + uint8_t preparedSeed[NFC3D_DRBG_MAX_SEED_SIZE]; + size_t preparedSeedSize; + + nfc3d_keygen_prepare_seed(baseKeys, baseSeed, preparedSeed, &preparedSeedSize); + nfc3d_drbg_generate_bytes(baseKeys->hmacKey, sizeof(baseKeys->hmacKey), preparedSeed, preparedSeedSize, (uint8_t *) derivedKeys, sizeof(*derivedKeys)); +} diff --git a/client/amiitool/keygen.h b/client/amiitool/keygen.h new file mode 100644 index 000000000..4d1c21cea --- /dev/null +++ b/client/amiitool/keygen.h @@ -0,0 +1,34 @@ +/* + * (c) 2015-2017 Marcos Del Sol Vives + * + * SPDX-License-Identifier: MIT + */ + +#ifndef HAVE_NFC3D_KEYGEN_H +#define HAVE_NFC3D_KEYGEN_H + +#include +#include + +#define NFC3D_KEYGEN_SEED_SIZE 64 + +#pragma pack(1) +typedef struct { + uint8_t hmacKey[16]; + char typeString[14]; + uint8_t rfu; + uint8_t magicBytesSize; + uint8_t magicBytes[16]; + uint8_t xorPad[32]; +} nfc3d_keygen_masterkeys; + +typedef struct { + const uint8_t aesKey[16]; + const uint8_t aesIV[16]; + const uint8_t hmacKey[16]; +} nfc3d_keygen_derivedkeys; +#pragma pack() + +void nfc3d_keygen(const nfc3d_keygen_masterkeys *baseKeys, const uint8_t *baseSeed, nfc3d_keygen_derivedkeys *derivedKeys); + +#endif diff --git a/client/cli.c b/client/cli.c deleted file mode 100644 index e7f8324ca..000000000 --- a/client/cli.c +++ /dev/null @@ -1,58 +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. -//----------------------------------------------------------------------------- -// Command line binary -//----------------------------------------------------------------------------- - -#include -#include "util_posix.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()) { 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 new file mode 100644 index 000000000..2b321946f --- /dev/null +++ b/client/cliparser/README.md @@ -0,0 +1,13 @@ +# 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 new file mode 100644 index 000000000..9d83dc33c --- /dev/null +++ b/client/cliparser/argtable3.c @@ -0,0 +1,4716 @@ +/******************************************************************************* + * 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" + +// On Windows isspace crashes app in case of using Unicode character set and string to be above ASCII +// so you have to use _istspace instead of space +#ifdef UNICODE +#include +#define ISSPACE _istspace +#else +#define ISSPACE isspace +#endif + +/******************************************************************************* + * This file is part of the argtable3 library. + * + * Copyright (C) 2013 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 + +#define ARG_ENABLE_TRACE 0 +#define ARG_ENABLE_LOG 1 + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + EMINCOUNT = 1, + EMAXCOUNT, + EBADINT, + // The same name define EOVERFLOW in errno.h on windows platform +#ifdef __STDC_WANT_SECURE_LIB__ + EOVERFLOW_, +#else + EOVERFLOW, +#endif + EBADDOUBLE, + EBADDATE, + EREGNOMATCH +}; + + +#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, ...); + +#ifdef __cplusplus +} +#endif + +#endif + +/******************************************************************************* + * 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 +#include + + +void dbg_printf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +#include "getopt.h" + +/* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */ +/* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl 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. + */ + +// $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $" + +/*- + * 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 0 +#include +#endif +#include +#include +#include + + +#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ + +#ifdef REPLACE_GETOPT +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 */ +const char *optarg; /* argument associated with option */ +#endif + +#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 "" + +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); +static int gcd(int, int); +static void permute_args(int, int, int, char *const *); + +static const 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 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 illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + + +#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_OPTER_MSG_SIZE 128 + +extern char opterrmsg[MAX_OPTER_MSG_SIZE]; +char opterrmsg[MAX_OPTER_MSG_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) +#ifdef __STDC_WANT_SECURE_LIB__ + _vsnprintf_s(opterrmsg, MAX_OPTER_MSG_SIZE, sizeof(opterrmsg) - 1, fmt, ap); +#else + _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap); +#endif + va_end(ap); + + 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) { + + /* + * compute lengths of blocks and number and size of cycles + */ + int nnonopts = panonopt_end - panonopt_start; + int nopts = opt_end - panonopt_end; + int ncycle = gcd(nnonopts, nopts); + int cyclelen = (opt_end - panonopt_start) / ncycle; + + for (int i = 0; i < ncycle; i++) { + int cstart = panonopt_end + i; + int pos = cstart; + for (int j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + char *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) { + const char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + 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; + 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) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (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, (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; + return (BADARG); + } + 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, + 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, 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; +#ifdef __STDC_WANT_SECURE_LIB__ + char *buffer = NULL; + size_t buffer_size = 0; + errno_t err = 0; +#endif + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + +#ifdef __STDC_WANT_SECURE_LIB__ + if (posixly_correct == -1) { + err = _dupenv_s(&buffer, &buffer_size, "POSIXLY_CORRECT") == 0; + posixly_correct = buffer != NULL; + if (buffer != NULL && err == 0) { + free(buffer); + } + } +#else + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); +#endif + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * 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; + + 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]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + 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; + if (*place == '-') + place++; /* --foo long option */ + 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); + 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; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + 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]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + 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); +} + +#ifdef REPLACE_GETOPT +/* + * 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)); +} +#endif /* REPLACE_GETOPT */ + +/* + * 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)); +} +/******************************************************************************* + * 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 +#include + +#include "argtable3.h" + + +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 = EMAXCOUNT; + } 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 = EBADDATE; + } + + 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) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_date_errorfn( + struct arg_date *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADDATE: { + struct tm tm; + char buff[200]; + + fprintf(fp, "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); + printf("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 *)calloc(1, nbytes); + if (result) { + /* 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); +} +/******************************************************************************* + * 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 + +#include "argtable3.h" + + +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 = EMAXCOUNT; + } 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 = EBADDOUBLE; + } + + 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) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_dbl_errorfn( + struct arg_dbl *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADDOUBLE: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, 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; + + /* 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 *)malloc(nbytes); + if (result) { + size_t addr; + size_t rem; + + /* 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; +} +/******************************************************************************* + * 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 + +#include "argtable3.h" + + +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, + FILE *fp, + int error, + const char *argval, + const char *progname) { + /* suppress unreferenced formal parameter warning */ + (void)parent; + + progname = progname ? progname : ""; + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch (error) { + case ARG_ELIMIT: + fputs("too many errors to display", fp); + break; + case ARG_EMALLOC: + fputs("insufficent memory", fp); + break; + case ARG_ENOMATCH: + fprintf(fp, "unexpected argument \"%s\"", argval); + break; + case ARG_EMISSARG: + fprintf(fp, "option \"%s\" requires an argument", argval); + break; + case ARG_ELONGOPT: + fprintf(fp, "invalid option \"%s\"", argval); + break; + default: + fprintf(fp, "invalid option \"-%c\"", error); + break; + } + + fputc('\n', fp); +} + + +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 *)malloc(nbytes); + if (result) { + /* 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(FILE *fp, 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], + fp, + end->error[i], + end->argval[i], + progname); + } +} +/******************************************************************************* + * 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 +#include + +#include "argtable3.h" + +#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 && result[1] == '\0') + 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 = EMAXCOUNT; + } 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) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_file_errorfn( + struct arg_file *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + default: + fprintf(fp, "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; + + /* 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 *)malloc(nbytes); + if (result) { + int i; + + /* 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; +} +/******************************************************************************* + * 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 +#include +#include + +#include "argtable3.h" + + +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 = EMAXCOUNT; + } 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 EBADINT; + } + } + } + } + + /* Safety check for integer overflow. WARNING: this check */ + /* achieves nothing on machines where size(int)==size(long). */ + if (val > INT_MAX || val < INT_MIN) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; +#else + errorcode = EOVERFLOW; +#endif + + /* 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)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1024; /* 1KB = 1024 */ + } else if (detectsuffix(end, "MB")) { /* megabytes */ + if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1048576; /* 1MB = 1024*1024 */ + } else if (detectsuffix(end, "GB")) { /* gigabytes */ + if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1073741824; /* 1GB = 1024*1024*1024 */ + } else if (!detectsuffix(end, "")) + errorcode = EBADINT; /* invalid suffix detected */ + + /* if success then store result in parent->ival[] array */ + if (errorcode == 0) + parent->ival[parent->count++] = 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) ? EMINCOUNT : 0; + /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ + return errorcode; +} + + +static void arg_int_errorfn( + struct arg_int *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADINT: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + +#ifdef __STDC_WANT_SECURE_LIB__ + case EOVERFLOW_: +#else + case EOVERFLOW: +#endif + fputs("integer overflow at option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, " "); + fprintf(fp, "(%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 *)malloc(nbytes); + if (result) { + /* 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; +} +/******************************************************************************* + * 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 + +#include "argtable3.h" + + +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 = EMAXCOUNT; + + 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) ? EMINCOUNT : 0; + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_lit_errorfn( + struct arg_lit *parent, + FILE *fp, + 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 EMINCOUNT: + fprintf(fp, "%s: missing option ", progname); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + fprintf(fp, "\n"); + break; + + case EMAXCOUNT: + fprintf(fp, "%s: extraneous option ", progname); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + } + + ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp, + 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 *)malloc(sizeof(struct arg_lit)); + if (result) { + /* 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; +} +/******************************************************************************* + * 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 + +#include "argtable3.h" + +struct arg_rem *arg_rem(const char *datatype, const char *glossary) { + struct arg_rem *result = (struct arg_rem *)malloc(sizeof(struct arg_rem)); + if (result) { + 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; +} + +/******************************************************************************* + * 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 +#include + +#include "argtable3.h" + + +#ifndef _TREX_H_ +#define _TREX_H_ +/*************************************************************** + T-Rex a tiny regular expression 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 + +#ifdef _UNICODE +#define TRexChar unsigned short +#define MAX_CHAR 0xFFFF +#define _TREXC(c) L##c +#define trex_strlen wcslen +#define trex_printf wprintf +#else +#define TRexChar char +#define MAX_CHAR 0xFF +#define _TREXC(c) (c) +#define trex_strlen strlen +#define trex_printf printf +#endif + +#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; + +TREX_API TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags); +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; + + if (parent->count == parent->hdr.maxcount) { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } 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 = EREGNOMATCH; + 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) ? EMINCOUNT : 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);*/ + return errorcode; +} + +static void arg_rex_errorfn(struct arg_rex *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EREGNOMATCH: + fputs("illegal value ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + default: { + //char errbuff[256]; + //regerror(errorcode, NULL, errbuff, sizeof(errbuff)); + //printf("%s\n", errbuff); + } + 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 */ + + result = (struct arg_rex *)malloc(nbytes); + if (result == NULL) + return result; + + /* init the arg_hdr struct */ + 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 _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 *)realloc(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; + } //else default + 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; + } + /* 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])); + 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))) + 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))) { + 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))) { + if (temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + } + 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))) { + if (capture != -1) { + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while ((n->next != -1) && (n = &exp->_nodes[n->next])); + + 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; + } + return NULL; +} + +/* public api */ +TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags) { + TRex *exp = (TRex *)malloc(sizeof(TRex)); + exp->_eol = exp->_bol = NULL; + exp->_p = pattern; + exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar); + exp->_nodes = (TRexNode *)malloc(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 = malloc(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 _DEBUG + { + int nsize, i; + TRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + 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 *) malloc(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) { + if (exp->_nodes) free(exp->_nodes); + if (exp->_jmpbuf) free(exp->_jmpbuf); + if (exp->_matches) free(exp->_matches); + free(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; +} +/******************************************************************************* + * 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 + +#include "argtable3.h" + + +static void arg_str_resetfn(struct arg_str *parent) { + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + 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 = EMAXCOUNT; + } 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->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) ? EMINCOUNT : 0; + + ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); + return errorcode; +} + + +static void arg_str_errorfn( + struct arg_str *parent, + FILE *fp, + 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 : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, 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; + + /* 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 *)malloc(nbytes); + if (result) { + int i; + + /* 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 initialising them to reference empty strings */ + for (i = 0; i < maxcount; i++) + result->sval[i] = ""; + } + + ARG_TRACE(("arg_strn() returns %p\n", result)); + return result; +} +/******************************************************************************* + * 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 +#include +#include +#include + +#include "argtable3.h" + +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; + + /* + * 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 *)malloc(nbytes); + if (result) { + int option_index = 0; + char *store; + + 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; + + /* 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 = malloc(len); + if (result) { + char *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); + if (!longoptions || !shortoptions) { + /* one or both memory allocs failed */ + arg_register_error(endtable, endtable, ARG_EMALLOC, NULL); + /* free anything that was allocated (this is null safe) */ + free(shortoptions); + free(longoptions); + return; + } + + /*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 */ + while ((copt = + getopt_long(argc, argv, shortoptions, longoptions->options, + NULL)) != -1) { + /* + 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; + } + } + } + + free(shortoptions); + free(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; + + /*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 **)malloc(sizeof(char *) * (argc + 1)); + if (argvcopy) { + int i; + + /* + 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[] */ + free(argvcopy); + } else { + /* memory alloc failed */ + arg_register_error(endtable, endtable, ARG_EMALLOC, NULL); + } + + 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, ","); +#ifdef __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, ","); +#ifdef __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); + } +} + + +/* this function should be deprecated because it doesnt consider optional argument values (ARG_HASOPTVALUE) */ +void arg_print_option(FILE *fp, + 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), + shortopts, + longopts, + datatype, + 0, + "|"); + + fputs(syntax, fp); + fputs(suffix, fp); +} + + +/* + * 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(FILE *fp, struct arg_hdr * *table) { + int tabindex; + const char *format1 = " -%c"; + const char *format2 = " [-%c"; + const 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)*/ + fprintf(fp, 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 */ + fprintf(fp, format2, table[tabindex]->shortopts[0]); + format2 = "%c"; + suffix = "]"; + } + + fprintf(fp, "%s", suffix); +} + + +void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) { + struct arg_hdr * *table = (struct arg_hdr * *)argtable; + int i, tabindex; + + /* print GNU style [OPTION] string */ + arg_print_gnuswitch(fp, 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), + 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++) + fprintf(fp, " %s", syntax); + + /* print optional instances enclosed in "[..]" */ + switch (table[tabindex]->maxcount - table[tabindex]->mincount) { + case 0: + break; + case 1: + fprintf(fp, " [%s]", syntax); + break; + case 2: + fprintf(fp, " [%s] [%s]", syntax, syntax); + break; + default: + fprintf(fp, " [%s]...", syntax); + break; + } + } + } + + if (suffix) + fprintf(fp, "%s", suffix); +} + + +void arg_print_syntaxv(FILE *fp, 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), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + "|"); + + /* print mandatory options */ + for (i = 0; i < table[tabindex]->mincount; i++) + fprintf(fp, " %s", syntax); + + /* print optional args enclosed in "[..]" */ + switch (table[tabindex]->maxcount - table[tabindex]->mincount) { + case 0: + break; + case 1: + fprintf(fp, " [%s]", syntax); + break; + case 2: + fprintf(fp, " [%s] [%s]", syntax, syntax); + break; + default: + fprintf(fp, " [%s]...", syntax); + break; + } + } + + if (suffix) + fprintf(fp, "%s", suffix); +} + + +void arg_print_glossary(FILE *fp, 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), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + ", "); + fprintf(fp, format, syntax, glossary); + } + } +} + + +/** + * 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(FILE *fp, + const unsigned lmargin, + const unsigned rmargin, + const char *text) { + const unsigned textlen = (unsigned)strlen(text); + unsigned line_start = 0; + unsigned line_end = textlen + 1; + const unsigned colwidth = (rmargin - lmargin) + 1; + + /* Someone doesn't like us... */ + if (line_end == line_start) { + fprintf(fp, "%s\n", text); + } + + while (line_end - 1 > line_start) { + /* Eat leading whitespaces. This is essential because while + wrapping lines, there will often be a whitespace at beginning + of line */ + while (ISSPACE(*(text + line_start))) + { line_start++; } + + if ((line_end - line_start) > colwidth) + { line_end = line_start + colwidth; } + + /* Find last whitespace, that fits into line */ + while ((line_end > line_start) + && (line_end - line_start > colwidth) + && !ISSPACE(*(text + line_end))) + { line_end--; } + + /* Do not print trailing whitespace. If this text + has got only one line, line_end now points to the + last char due to initialization. */ + line_end--; + + /* Output line of text */ + while (line_start < line_end) { + fputc(*(text + line_start), fp); + line_start++; + } + fputc('\n', fp); + + /* Initialize another line */ + if (line_end + 1 < textlen) { + unsigned i; + + for (i = 0; i < lmargin; i++) + { fputc(' ', fp); } + + line_end = textlen; + } + + /* If we have to print another line, get also the last char. */ + line_end++; + + } /* 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(FILE *fp, 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), + shortopts, + longopts, + datatype, + table[tabindex]->flag & ARG_HASOPTVALUE, + ", "); + + /* If syntax fits not into column, print glossary in new line... */ + if (strlen(syntax) > 25) { + fprintf(fp, " %-25s %s\n", syntax, ""); + *syntax = '\0'; + } + + fprintf(fp, " %-25s ", syntax); + arg_print_formatted(fp, 28, 79, glossary); + } + } /* for each table entry */ + + fputc('\n', fp); +} + + +/** + * 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; + free(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; + + free(table[tabindex]); + table[tabindex] = NULL; + }; +} + diff --git a/client/cliparser/argtable3.h b/client/cliparser/argtable3.h new file mode 100644 index 000000000..c3ec479ea --- /dev/null +++ b/client/cliparser/argtable3.h @@ -0,0 +1,294 @@ +/******************************************************************************* + * 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 + +/* bit masks for arg_hdr.flag */ +enum { + ARG_TERMINATOR = 0x1, + ARG_HASVALUE = 0x2, + ARG_HASOPTVALUE = 0x4 +}; + +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, FILE *fp, int error, const char *argval, const char *progname); + + +/* +* 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. +*/ +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 */ +}; + +struct arg_rem { + struct arg_hdr hdr; /* The mandatory argtable header struct */ +}; + +struct arg_lit { + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ +}; + +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 */ +}; + +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 */ +}; + +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 */ +}; + +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 */ +}; + +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) */ +}; + +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 */ +}; + +enum {ARG_ELIMIT = 1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG}; +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_xxx constructor functions *********************************/ + +struct arg_rem *arg_rem(const char *datatype, const char *glossary); + +struct arg_lit *arg_lit0(const char *shortopts, + const char *longopts, + const char *glossary); +struct arg_lit *arg_lit1(const char *shortopts, + const char *longopts, + const char *glossary); +struct arg_lit *arg_litn(const char *shortopts, + const char *longopts, + int mincount, + int maxcount, + const char *glossary); + +struct arg_key *arg_key0(const char *keyword, + int flags, + const char *glossary); +struct arg_key *arg_key1(const char *keyword, + int flags, + const char *glossary); +struct arg_key *arg_keyn(const char *keyword, + int flags, + int mincount, + int maxcount, + const char *glossary); + +struct arg_int *arg_int0(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_int *arg_int1(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_int *arg_intn(const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_dbl *arg_dbl0(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_dbl *arg_dbl1(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_dbl *arg_dbln(const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_str *arg_str0(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_str *arg_str1(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_str *arg_strn(const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_rex *arg_rex0(const char *shortopts, + const char *longopts, + const char *pattern, + const char *datatype, + int flags, + const char *glossary); +struct arg_rex *arg_rex1(const char *shortopts, + const char *longopts, + const char *pattern, + const char *datatype, + int flags, + const char *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); + +struct arg_file *arg_file0(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_file *arg_file1(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_file *arg_filen(const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); + +struct arg_date *arg_date0(const char *shortopts, + const char *longopts, + const char *format, + const char *datatype, + const char *glossary); +struct arg_date *arg_date1(const char *shortopts, + const char *longopts, + const char *format, + const char *datatype, + const char *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); + +struct arg_end *arg_end(int maxcount); + + +/**** other functions *******************************************/ +int arg_nullcheck(void **argtable); +int arg_parse(int argc, char **argv, void **argtable); +void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix); +void arg_print_syntax(FILE *fp, void **argtable, const char *suffix); +void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix); +void arg_print_glossary(FILE *fp, void **argtable, const char *format); +void arg_print_glossary_gnu(FILE *fp, void **argtable); +void arg_print_errors(FILE *fp, struct arg_end *end, const char *progname); +void arg_freetable(void **argtable, size_t n); + +/**** deprecated functions, for back-compatibility only ********/ +void arg_free(void **argtable); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/client/cliparser/cliparser.c b/client/cliparser/cliparser.c new file mode 100644 index 000000000..ae2124085 --- /dev/null +++ b/client/cliparser/cliparser.c @@ -0,0 +1,204 @@ +//----------------------------------------------------------------------------- +// 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; +const char *programName = NULL; +const char *programHint = NULL; +const char *programHelp = NULL; +char buf[500] = {0}; + +int CLIParserInit(const char *vprogramName, const char *vprogramHint, const 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 tmp_buf[256] = {0}; + int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX + if (res || !ibuf) + return res; + + switch (param_gethex_to_eol((char *)tmp_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 tmp_buf[256] = {0}; + int ibuf = 0; + + for (int i = 0; i < argstr->count; i++) { + int len = strlen(argstr->sval[i]); + memcpy(&tmp_buf[ibuf], argstr->sval[i], len); + ibuf += len; + } + tmp_buf[ibuf] = 0; + + if (!ibuf) + return 0; + + if (ibuf > maxdatalen) + return 2; + + memcpy(data, tmp_buf, ibuf); + *datalen = ibuf; + + return 0; +} + + diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h new file mode 100644 index 000000000..7da509757 --- /dev/null +++ b/client/cliparser/cliparser.h @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// 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 +//----------------------------------------------------------------------------- + +#ifndef __CLIPARSER_H +#define __CLIPARSER_H +#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 PM3_ESOFT;} +#define CLIGetHexBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return PM3_ESOFT;} +#define CLIGetHexWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return PM3_ESOFT;} +#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return PM3_ESOFT;} + +int CLIParserInit(const char *vprogramName, const char *vprogramHint, const char *vprogramHelp); +int CLIParserParseString(const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec); +int CLIParserParseStringEx(const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData); +int CLIParserParseArg(int argc, char **argv, void *vargtable[], size_t vargtableLen, bool allowEmptyExec); +void CLIParserFree(void); + +int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); +int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); +#endif diff --git a/client/cliparser/getopt.h b/client/cliparser/getopt.h new file mode 100644 index 000000000..bf645feb5 --- /dev/null +++ b/client/cliparser/getopt.h @@ -0,0 +1,80 @@ +/* $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. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +#include + +/* + * 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; +}; + +__BEGIN_DECLS +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 const 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 +__END_DECLS + +#endif /* !_GETOPT_H_ */ diff --git a/client/cmdanalyse.c b/client/cmdanalyse.c index 1c65b8cc4..1eee47c78 100644 --- a/client/cmdanalyse.c +++ b/client/cmdanalyse.c @@ -11,74 +11,74 @@ static int CmdHelp(const char *Cmd); -int usage_analyse_lcr(void) { - PrintAndLogEx(NORMAL, "Specifying the bytes of a UID with a known LRC will find the last byte value"); - PrintAndLogEx(NORMAL, "needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: analyse lcr [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " bytes to calc missing XOR in a LCR"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " analyse lcr 04008064BA"); - PrintAndLogEx(NORMAL, "expected output: Target (BA) requires final LRC XOR byte value: 5A"); - return 0; +static int usage_analyse_lcr(void) { + PrintAndLogEx(NORMAL, "Specifying the bytes of a UID with a known LRC will find the last byte value"); + PrintAndLogEx(NORMAL, "needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: analyse lcr [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " bytes to calc missing XOR in a LCR"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " analyse lcr 04008064BA"); + PrintAndLogEx(NORMAL, "expected output: Target (BA) requires final LRC XOR byte value: 5A"); + return 0; } -int usage_analyse_checksum(void) { - PrintAndLogEx(NORMAL, "The bytes will be added with eachother and than limited with the applied mask"); - PrintAndLogEx(NORMAL, "Finally compute ones' complement of the least significant bytes"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: analyse chksum [h] [v] b m "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " v supress header"); - PrintAndLogEx(NORMAL, " b bytes to calc missing XOR in a LCR"); - PrintAndLogEx(NORMAL, " m bit mask to limit the outpuyt"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " analyse chksum b 137AF00A0A0D m FF"); - PrintAndLogEx(NORMAL, "expected output: 0x61"); - return 0; +static int usage_analyse_checksum(void) { + PrintAndLogEx(NORMAL, "The bytes will be added with eachother and than limited with the applied mask"); + PrintAndLogEx(NORMAL, "Finally compute ones' complement of the least significant bytes"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: analyse chksum [h] [v] b m "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " v supress header"); + PrintAndLogEx(NORMAL, " b bytes to calc missing XOR in a LCR"); + PrintAndLogEx(NORMAL, " m bit mask to limit the outpuyt"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " analyse chksum b 137AF00A0A0D m FF"); + PrintAndLogEx(NORMAL, "expected output: 0x61"); + return 0; } -int usage_analyse_crc(void){ - PrintAndLogEx(NORMAL, "A stub method to test different crc implementations inside the PM3 sourcecode. Just because you figured out the poly, doesn't mean you get the desired output"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: analyse crc [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " bytes to calc crc"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " analyse crc 137AF00A0A0D"); - return 0; +static int usage_analyse_crc(void) { + PrintAndLogEx(NORMAL, "A stub method to test different crc implementations inside the PM3 sourcecode. Just because you figured out the poly, doesn't mean you get the desired output"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: analyse crc [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " bytes to calc crc"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " analyse crc 137AF00A0A0D"); + return 0; } -int usage_analyse_nuid(void){ - PrintAndLogEx(NORMAL, "Generate 4byte NUID from 7byte UID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: analyse hid [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " input bytes (14 hexsymbols)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " analyse nuid 11223344556677"); - return 0; +static int usage_analyse_nuid(void) { + PrintAndLogEx(NORMAL, "Generate 4byte NUID from 7byte UID"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: analyse hid [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " input bytes (14 hexsymbols)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " analyse nuid 11223344556677"); + return 0; } -int usage_analyse_a(void) { - PrintAndLogEx(NORMAL, "Iceman's personal garbage test command"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: analyse a [h] d "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " d bytes to send to device"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " analyse a d 137AF00A0A0D"); - return 0; +static int usage_analyse_a(void) { + PrintAndLogEx(NORMAL, "Iceman's personal garbage test command"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: analyse a [h] d "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " d bytes to send to device"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " analyse a d 137AF00A0A0D"); + return 0; } -static uint8_t calculateLRC( uint8_t* bytes, uint8_t len) { +static uint8_t calculateLRC(uint8_t *bytes, uint8_t len) { uint8_t LRC = 0; for (uint8_t i = 0; i < len; i++) LRC ^= bytes[i]; @@ -92,593 +92,557 @@ static uint16_t matrixadd ( uint8_t* bytes, uint8_t len){ 0x72 | 0111 0010 0x5e | 0101 1110 ----------------- - C32F 9d74 + C32F 9d74 - return 0; + return 0; } */ /* static uint16_t shiftadd ( uint8_t* bytes, uint8_t len){ - return 0; + return 0; } */ -static uint16_t calcSumCrumbAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumCrumbAdd(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { sum += CRUMB(bytes[i], 0); - sum += CRUMB(bytes[i], 2); - sum += CRUMB(bytes[i], 4); - sum += CRUMB(bytes[i], 6); - } - sum &= mask; + sum += CRUMB(bytes[i], 2); + sum += CRUMB(bytes[i], 4); + sum += CRUMB(bytes[i], 6); + } + sum &= mask; return sum; } -static uint16_t calcSumCrumbAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { - return (~calcSumCrumbAdd(bytes, len, mask) & mask); +static uint16_t calcSumCrumbAddOnes(uint8_t *bytes, uint8_t len, uint32_t mask) { + return (~calcSumCrumbAdd(bytes, len, mask) & mask); } -static uint16_t calcSumNibbleAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumNibbleAdd(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { sum += NIBBLE_LOW(bytes[i]); - sum += NIBBLE_HIGH(bytes[i]); - } - sum &= mask; + sum += NIBBLE_HIGH(bytes[i]); + } + sum &= mask; return sum; } -static uint16_t calcSumNibbleAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask){ - return (~calcSumNibbleAdd(bytes, len, mask) & mask); +static uint16_t calcSumNibbleAddOnes(uint8_t *bytes, uint8_t len, uint32_t mask) { + return (~calcSumNibbleAdd(bytes, len, mask) & mask); } -static uint16_t calcSumCrumbXor( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumCrumbXor(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { sum ^= CRUMB(bytes[i], 0); - sum ^= CRUMB(bytes[i], 2); - sum ^= CRUMB(bytes[i], 4); - sum ^= CRUMB(bytes[i], 6); - } - sum &= mask; + sum ^= CRUMB(bytes[i], 2); + sum ^= CRUMB(bytes[i], 4); + sum ^= CRUMB(bytes[i], 6); + } + sum &= mask; return sum; } -static uint16_t calcSumNibbleXor( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumNibbleXor(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { sum ^= NIBBLE_LOW(bytes[i]); - sum ^= NIBBLE_HIGH(bytes[i]); - } - sum &= mask; + sum ^= NIBBLE_HIGH(bytes[i]); + } + sum &= mask; return sum; } -static uint16_t calcSumByteXor( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumByteXor(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { - sum ^= bytes[i]; - } - sum &= mask; + sum ^= bytes[i]; + } + sum &= mask; return sum; } -static uint16_t calcSumByteAdd( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumByteAdd(uint8_t *bytes, uint8_t len, uint32_t mask) { uint16_t sum = 0; for (uint8_t i = 0; i < len; i++) { - sum += bytes[i]; - } - sum &= mask; + sum += bytes[i]; + } + sum &= mask; return sum; } // Ones complement -static uint16_t calcSumByteAddOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { - return (~calcSumByteAdd(bytes, len, mask) & mask); +static uint16_t calcSumByteAddOnes(uint8_t *bytes, uint8_t len, uint32_t mask) { + return (~calcSumByteAdd(bytes, len, mask) & mask); } -static uint16_t calcSumByteSub( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumByteSub(uint8_t *bytes, uint8_t len, uint32_t mask) { uint8_t sum = 0; for (uint8_t i = 0; i < len; i++) { - sum -= bytes[i]; - } - sum &= mask; + sum -= bytes[i]; + } + sum &= mask; return sum; } -static uint16_t calcSumByteSubOnes( uint8_t* bytes, uint8_t len, uint32_t mask){ - return (~calcSumByteSub(bytes, len, mask) & mask); +static uint16_t calcSumByteSubOnes(uint8_t *bytes, uint8_t len, uint32_t mask) { + return (~calcSumByteSub(bytes, len, mask) & mask); } -static uint16_t calcSumNibbleSub( uint8_t* bytes, uint8_t len, uint32_t mask) { +static uint16_t calcSumNibbleSub(uint8_t *bytes, uint8_t len, uint32_t mask) { uint8_t sum = 0; for (uint8_t i = 0; i < len; i++) { sum -= NIBBLE_LOW(bytes[i]); - sum -= NIBBLE_HIGH(bytes[i]); - } - sum &= mask; + sum -= NIBBLE_HIGH(bytes[i]); + } + sum &= mask; return sum; } -static uint16_t calcSumNibbleSubOnes( uint8_t* bytes, uint8_t len, uint32_t mask) { - return (~calcSumNibbleSub(bytes, len, mask) & mask); +static uint16_t calcSumNibbleSubOnes(uint8_t *bytes, uint8_t len, uint32_t mask) { + return (~calcSumNibbleSub(bytes, len, mask) & mask); } // BSD shift checksum 8bit version -static uint16_t calcBSDchecksum8( uint8_t* bytes, uint8_t len, uint32_t mask){ - uint16_t sum = 0; - for(uint8_t i = 0; i < len; i++){ - sum = ((sum & 0xFF) >> 1) | ((sum & 0x1) << 7); // rotate accumulator - sum += bytes[i]; // add next byte - sum &= 0xFF; // - } - sum &= mask; - return sum; +static uint16_t calcBSDchecksum8(uint8_t *bytes, uint8_t len, uint32_t mask) { + uint16_t sum = 0; + for (uint8_t i = 0; i < len; i++) { + sum = ((sum & 0xFF) >> 1) | ((sum & 0x1) << 7); // rotate accumulator + sum += bytes[i]; // add next byte + sum &= 0xFF; // + } + sum &= mask; + return sum; } // BSD shift checksum 4bit version -static uint16_t calcBSDchecksum4( uint8_t* bytes, uint8_t len, uint32_t mask){ - uint16_t sum = 0; - for(uint8_t i = 0; i < len; i++){ - sum = ((sum & 0xF) >> 1) | ((sum & 0x1) << 3); // rotate accumulator - sum += NIBBLE_HIGH(bytes[i]); // add high nibble - sum &= 0xF; // - sum = ((sum & 0xF) >> 1) | ((sum & 0x1) << 3); // rotate accumulator - sum += NIBBLE_LOW(bytes[i]); // add low nibble - sum &= 0xF; // - } - sum &= mask; - return sum; +static uint16_t calcBSDchecksum4(uint8_t *bytes, uint8_t len, uint32_t mask) { + uint16_t sum = 0; + for (uint8_t i = 0; i < len; i++) { + sum = ((sum & 0xF) >> 1) | ((sum & 0x1) << 3); // rotate accumulator + sum += NIBBLE_HIGH(bytes[i]); // add high nibble + sum &= 0xF; // + sum = ((sum & 0xF) >> 1) | ((sum & 0x1) << 3); // rotate accumulator + sum += NIBBLE_LOW(bytes[i]); // add low nibble + sum &= 0xF; // + } + sum &= mask; + return sum; } // measuring LFSR maximum length -int CmdAnalyseLfsr(const char *Cmd){ +static int CmdAnalyseLfsr(const char *Cmd) { - uint16_t start_state = 0; /* Any nonzero start state will work. */ - uint16_t lfsr = start_state; - //uint32_t period = 0; + uint8_t iv = param_get8ex(Cmd, 0, 0, 16); + uint8_t find = param_get8ex(Cmd, 1, 0, 16); - uint8_t iv = param_get8ex(Cmd, 0, 0, 16); - uint8_t find = param_get8ex(Cmd, 1, 0, 16); - - PrintAndLogEx(NORMAL, "LEGIC LFSR IV 0x%02X: \n", iv); - PrintAndLogEx(NORMAL, " bit# | lfsr | ^0x40 | 0x%02X ^ lfsr \n",find); - - for (uint8_t i = 0x01; i < 0x30; i += 1) { - //period = 0; - legic_prng_init(iv); - legic_prng_forward(i); - lfsr = legic_prng_get_bits(12); + PrintAndLogEx(NORMAL, "LEGIC LFSR IV 0x%02X: \n", iv); + PrintAndLogEx(NORMAL, " bit# | lfsr | ^0x40 | 0x%02X ^ lfsr \n", find); - PrintAndLogEx(NORMAL, " %02X | %03X | %03X | %03X \n",i, lfsr, 0x40 ^ lfsr, find ^ lfsr); - } - return 0; + for (uint8_t i = 0x01; i < 0x30; i += 1) { + legic_prng_init(iv); + legic_prng_forward(i); + uint16_t lfsr = legic_prng_get_bits(12); /* Any nonzero start state will work. */ + PrintAndLogEx(NORMAL, " %02X | %03X | %03X | %03X \n", i, lfsr, 0x40 ^ lfsr, find ^ lfsr); + } + return 0; } -int CmdAnalyseLCR(const char *Cmd) { - uint8_t data[50]; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0|| cmdp == 'h' || cmdp == 'H') return usage_analyse_lcr(); - - int len = 0; - switch (param_gethex_to_eol(Cmd, 0, data, sizeof(data), &len)) { - case 1: - PrintAndLogEx(WARNING, "Invalid HEX value."); - return 1; - case 2: - PrintAndLogEx(WARNING, "Too many bytes. Max %d bytes", sizeof(data)); - return 1; - case 3: - PrintAndLogEx(WARNING, "Hex must have even number of digits."); - return 1; - } - uint8_t finalXor = calculateLRC(data, len); - PrintAndLogEx(NORMAL, "Target [%02X] requires final LRC XOR byte value: 0x%02X",data[len-1] ,finalXor); - return 0; +static int CmdAnalyseLCR(const char *Cmd) { + uint8_t data[50]; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_analyse_lcr(); + + int len = 0; + switch (param_gethex_to_eol(Cmd, 0, data, sizeof(data), &len)) { + case 1: + PrintAndLogEx(WARNING, "Invalid HEX value."); + return 1; + case 2: + PrintAndLogEx(WARNING, "Too many bytes. Max %d bytes", sizeof(data)); + return 1; + case 3: + PrintAndLogEx(WARNING, "Hex must have even number of digits."); + return 1; + } + uint8_t finalXor = calculateLRC(data, len); + PrintAndLogEx(NORMAL, "Target [%02X] requires final LRC XOR byte value: 0x%02X", data[len - 1], finalXor); + return 0; } -int CmdAnalyseCRC(const char *Cmd) { +static int CmdAnalyseCRC(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') return usage_analyse_crc(); - - int len = strlen(Cmd); - if ( len & 1 ) return usage_analyse_crc(); - - // add 1 for null terminator. - uint8_t *data = calloc(len+1, sizeof(uint8_t)); - if ( !data ) return 1; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_analyse_crc(); - if ( param_gethex(Cmd, 0, data, len)) { - free(data); - return usage_analyse_crc(); - } - len >>= 1; + int len = strlen(Cmd); + if (len & 1) return usage_analyse_crc(); - PrintAndLogEx(NORMAL, "\nTests with (%d) | %s",len, sprint_hex(data, len)); - - // 51 f5 7a d6 - uint8_t uid[] = {0x51, 0xf5, 0x7a, 0xd6}; //12 34 56 - init_table(CRC_LEGIC); - uint8_t legic8 = CRC8Legic(uid, sizeof(uid)); - PrintAndLogEx(NORMAL, "Legic 16 | %X (EF6F expected) [legic8 = %02x]", crc16_legic(data, len, legic8), legic8); - init_table(CRC_FELICA); - PrintAndLogEx(NORMAL, "FeliCa | %X ", crc16_xmodem(data, len)); - - PrintAndLogEx(NORMAL, "\nTests of reflection. Current methods in source code"); - PrintAndLogEx(NORMAL, " reflect(0x3e23L,3) is %04X == 0x3e26", reflect(0x3e23L,3) ); - PrintAndLogEx(NORMAL, " reflect8(0x80) is %02X == 0x01", reflect8(0x80)); - PrintAndLogEx(NORMAL, " reflect16(0x8000) is %04X == 0x0001", reflect16(0xc6c6)); - - uint8_t b1, b2; - // ISO14443 crc B - compute_crc(CRC_14443_B, data, len, &b1, &b2); - uint16_t crcBB_1 = b1 << 8 | b2; - uint16_t bbb = crc(CRC_14443_B, data, len); - PrintAndLogEx(NORMAL, "ISO14443 crc B | %04x == %04x \n", crcBB_1, bbb ); - - - // Test of CRC16, '123456789' string. - // - - PrintAndLogEx(NORMAL, "\n\nStandard test with 31 32 33 34 35 36 37 38 39 '123456789'\n\n"); - uint8_t dataStr[] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39 }; - legic8 = CRC8Legic(dataStr, sizeof(dataStr)); + // add 1 for null terminator. + uint8_t *data = calloc(len + 1, sizeof(uint8_t)); + if (!data) return 1; - //these below has been tested OK. - PrintAndLogEx(NORMAL, "Confirmed CRC Implementations"); - PrintAndLogEx(NORMAL, "-------------------------------------\n"); - PrintAndLogEx(NORMAL, "CRC 8 based\n\n"); - PrintAndLogEx(NORMAL, "LEGIC: CRC8 : %X (C6 expected)", legic8); - PrintAndLogEx(NORMAL, "MAXIM: CRC8 : %X (A1 expected)", CRC8Maxim(dataStr, sizeof(dataStr))); - PrintAndLogEx(NORMAL, "-------------------------------------\n"); - PrintAndLogEx(NORMAL, "CRC16 based\n\n"); + if (param_gethex(Cmd, 0, data, len)) { + free(data); + return usage_analyse_crc(); + } + len >>= 1; - // input from commandline - PrintAndLogEx(NORMAL, "CCITT | %X (29B1 expected)", crc(CRC_CCITT, dataStr, sizeof(dataStr))); - - uint8_t poll[] = {0xb2,0x4d,0x12,0x01,0x01,0x2e,0x3d,0x17,0x26,0x47,0x80, 0x95,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f}; - PrintAndLogEx(NORMAL, "FeliCa | %04X (B37F expected)", crc(CRC_FELICA, poll+2, sizeof(poll)-4)); - PrintAndLogEx(NORMAL, "FeliCa | %04X (0000 expected)", crc(CRC_FELICA, poll+2, sizeof(poll)-2)); - - uint8_t sel_corr[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01}; - PrintAndLogEx(NORMAL, "iCLASS | %04x (0143 expected)", crc(CRC_ICLASS, sel_corr, sizeof(sel_corr)-2)); - PrintAndLogEx(NORMAL, "---------------------------------------------------------------\n\n\n"); - - // ISO14443 crc A - compute_crc(CRC_14443_A, dataStr, sizeof(dataStr), &b1, &b2); - uint16_t crcAA = b1 << 8 | b2; - PrintAndLogEx(NORMAL, "ISO14443 crc A | %04x or %04x (BF05 expected)\n", crcAA, crc(CRC_14443_A, dataStr, sizeof(dataStr)) ); - - // ISO14443 crc B - compute_crc(CRC_14443_B, dataStr, sizeof(dataStr), &b1, &b2); - uint16_t crcBB = b1 << 8 | b2; - PrintAndLogEx(NORMAL, "ISO14443 crc B | %04x or %04x (906E expected)\n", crcBB, crc(CRC_14443_B, dataStr, sizeof(dataStr)) ); + PrintAndLogEx(NORMAL, "\nTests with (%d) | %s", len, sprint_hex(data, len)); - // ISO15693 crc (x.25) - compute_crc(CRC_15693, dataStr, sizeof(dataStr), &b1, &b2); - uint16_t crcCC = b1 << 8 | b2; - PrintAndLogEx(NORMAL, "ISO15693 crc X25| %04x or %04x (906E expected)\n", crcCC, crc(CRC_15693, dataStr, sizeof(dataStr)) ); + // 51 f5 7a d6 + uint8_t uid[] = {0x51, 0xf5, 0x7a, 0xd6}; //12 34 56 + init_table(CRC_LEGIC); + uint8_t legic8 = CRC8Legic(uid, sizeof(uid)); + PrintAndLogEx(NORMAL, "Legic 16 | %X (EF6F expected) [legic8 = %02x]", crc16_legic(data, len, legic8), legic8); + init_table(CRC_FELICA); + PrintAndLogEx(NORMAL, "FeliCa | %X ", crc16_xmodem(data, len)); - // ICLASS - compute_crc(CRC_ICLASS, dataStr, sizeof(dataStr), &b1, &b2); - uint16_t crcDD = b1 << 8 | b2; - PrintAndLogEx(NORMAL, "ICLASS crc | %04x or %04x\n", crcDD, crc(CRC_ICLASS, dataStr, sizeof(dataStr)) ); + PrintAndLogEx(NORMAL, "\nTests of reflection. Current methods in source code"); + PrintAndLogEx(NORMAL, " reflect(0x3e23L,3) is %04X == 0x3e26", reflect(0x3e23L, 3)); + PrintAndLogEx(NORMAL, " reflect8(0x80) is %02X == 0x01", reflect8(0x80)); + PrintAndLogEx(NORMAL, " reflect16(0x8000) is %04X == 0x0001", reflect16(0xc6c6)); - // FeliCa - compute_crc(CRC_FELICA, dataStr, sizeof(dataStr), &b1, &b2); - uint16_t crcEE = b1 << 8 | b2; - PrintAndLogEx(NORMAL, "FeliCa | %04x or %04x (31C3 expected)\n", crcEE, crc(CRC_FELICA, dataStr, sizeof(dataStr))); - - free(data); - return 0; + uint8_t b1, b2; + // ISO14443 crc B + compute_crc(CRC_14443_B, data, len, &b1, &b2); + uint16_t crcBB_1 = b1 << 8 | b2; + uint16_t bbb = Crc16ex(CRC_14443_B, data, len); + PrintAndLogEx(NORMAL, "ISO14443 crc B | %04x == %04x \n", crcBB_1, bbb); + + + // Test of CRC16, '123456789' string. + // + + PrintAndLogEx(NORMAL, "\n\nStandard test with 31 32 33 34 35 36 37 38 39 '123456789'\n\n"); + uint8_t dataStr[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 }; + legic8 = CRC8Legic(dataStr, sizeof(dataStr)); + + //these below has been tested OK. + PrintAndLogEx(NORMAL, "Confirmed CRC Implementations"); + PrintAndLogEx(NORMAL, "-------------------------------------\n"); + PrintAndLogEx(NORMAL, "CRC 8 based\n\n"); + PrintAndLogEx(NORMAL, "LEGIC: CRC8 : %X (C6 expected)", legic8); + PrintAndLogEx(NORMAL, "MAXIM: CRC8 : %X (A1 expected)", CRC8Maxim(dataStr, sizeof(dataStr))); + PrintAndLogEx(NORMAL, "-------------------------------------\n"); + PrintAndLogEx(NORMAL, "CRC16 based\n\n"); + + // input from commandline + PrintAndLogEx(NORMAL, "CCITT | %X (29B1 expected)", Crc16ex(CRC_CCITT, dataStr, sizeof(dataStr))); + + uint8_t poll[] = {0xb2, 0x4d, 0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f}; + PrintAndLogEx(NORMAL, "FeliCa | %04X (B37F expected)", Crc16ex(CRC_FELICA, poll + 2, sizeof(poll) - 4)); + PrintAndLogEx(NORMAL, "FeliCa | %04X (0000 expected)", Crc16ex(CRC_FELICA, poll + 2, sizeof(poll) - 2)); + + uint8_t sel_corr[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01}; + PrintAndLogEx(NORMAL, "iCLASS | %04x (0143 expected)", Crc16ex(CRC_ICLASS, sel_corr, sizeof(sel_corr) - 2)); + PrintAndLogEx(NORMAL, "---------------------------------------------------------------\n\n\n"); + + // ISO14443 crc A + compute_crc(CRC_14443_A, dataStr, sizeof(dataStr), &b1, &b2); + uint16_t crcAA = b1 << 8 | b2; + PrintAndLogEx(NORMAL, "ISO14443 crc A | %04x or %04x (BF05 expected)\n", crcAA, Crc16ex(CRC_14443_A, dataStr, sizeof(dataStr))); + + // ISO14443 crc B + compute_crc(CRC_14443_B, dataStr, sizeof(dataStr), &b1, &b2); + uint16_t crcBB = b1 << 8 | b2; + PrintAndLogEx(NORMAL, "ISO14443 crc B | %04x or %04x (906E expected)\n", crcBB, Crc16ex(CRC_14443_B, dataStr, sizeof(dataStr))); + + // ISO15693 crc (x.25) + compute_crc(CRC_15693, dataStr, sizeof(dataStr), &b1, &b2); + uint16_t crcCC = b1 << 8 | b2; + PrintAndLogEx(NORMAL, "ISO15693 crc X25| %04x or %04x (906E expected)\n", crcCC, Crc16ex(CRC_15693, dataStr, sizeof(dataStr))); + + // ICLASS + compute_crc(CRC_ICLASS, dataStr, sizeof(dataStr), &b1, &b2); + uint16_t crcDD = b1 << 8 | b2; + PrintAndLogEx(NORMAL, "ICLASS crc | %04x or %04x\n", crcDD, Crc16ex(CRC_ICLASS, dataStr, sizeof(dataStr))); + + // FeliCa + compute_crc(CRC_FELICA, dataStr, sizeof(dataStr), &b1, &b2); + uint16_t crcEE = b1 << 8 | b2; + PrintAndLogEx(NORMAL, "FeliCa | %04x or %04x (31C3 expected)\n", crcEE, Crc16ex(CRC_FELICA, dataStr, sizeof(dataStr))); + + free(data); + return 0; } -int CmdAnalyseCHKSUM(const char *Cmd){ - - uint8_t data[50]; - uint8_t cmdp = 0; - uint32_t mask = 0xFFFF; - bool errors = false; - bool useHeader = false; - int len = 0; - memset(data, 0x0, sizeof(data)); - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'b': - case 'B': - param_gethex_ex(Cmd, cmdp+1, data, &len); - if ( len%2 ) errors = true; - len >>= 1; - cmdp += 2; - break; - case 'm': - case 'M': - mask = param_get32ex(Cmd, cmdp+1, 0, 16); - cmdp += 2; - break; - case 'v': - case 'V': - useHeader = true; - cmdp++; - break; - case 'h': - case 'H': - return usage_analyse_checksum(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0 ) return usage_analyse_checksum(); - - if (useHeader) { - PrintAndLogEx(NORMAL, " add | sub | add 1's compl | sub 1's compl | xor"); - PrintAndLogEx(NORMAL, "byte nibble crumb | byte nibble | byte nibble cumb | byte nibble | byte nibble cumb | BSD |"); - PrintAndLogEx(NORMAL, "------------------+-------------+------------------+-----------------+--------------------"); - } - PrintAndLogEx(NORMAL, "0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X |\n", - calcSumByteAdd(data, len, mask) - , calcSumNibbleAdd(data, len, mask) - , calcSumCrumbAdd(data, len, mask) - , calcSumByteSub(data, len, mask) - , calcSumNibbleSub(data, len, mask) - , calcSumByteAddOnes(data, len, mask) - , calcSumNibbleAddOnes(data, len, mask) - , calcSumCrumbAddOnes(data, len, mask) - , calcSumByteSubOnes(data, len, mask) - , calcSumNibbleSubOnes(data, len, mask) - , calcSumByteXor(data, len, mask) - , calcSumNibbleXor(data, len, mask) - , calcSumCrumbXor(data, len, mask) - , calcBSDchecksum8(data, len, mask) - , calcBSDchecksum4(data, len, mask) - ); - return 0; +static int CmdAnalyseCHKSUM(const char *Cmd) { + + uint8_t data[50]; + uint8_t cmdp = 0; + uint32_t mask = 0xFFFF; + bool errors = false; + bool useHeader = false; + int len = 0; + memset(data, 0x0, sizeof(data)); + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (param_getchar(Cmd, cmdp)) { + case 'b': + case 'B': + param_gethex_ex(Cmd, cmdp + 1, data, &len); + if (len % 2) errors = true; + len >>= 1; + cmdp += 2; + break; + case 'm': + case 'M': + mask = param_get32ex(Cmd, cmdp + 1, 0, 16); + cmdp += 2; + break; + case 'v': + case 'V': + useHeader = true; + cmdp++; + break; + case 'h': + case 'H': + return usage_analyse_checksum(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || cmdp == 0) return usage_analyse_checksum(); + + if (useHeader) { + PrintAndLogEx(NORMAL, " add | sub | add 1's compl | sub 1's compl | xor"); + PrintAndLogEx(NORMAL, "byte nibble crumb | byte nibble | byte nibble cumb | byte nibble | byte nibble cumb | BSD |"); + PrintAndLogEx(NORMAL, "------------------+-------------+------------------+-----------------+--------------------"); + } + PrintAndLogEx(NORMAL, "0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X |\n", + calcSumByteAdd(data, len, mask) + , calcSumNibbleAdd(data, len, mask) + , calcSumCrumbAdd(data, len, mask) + , calcSumByteSub(data, len, mask) + , calcSumNibbleSub(data, len, mask) + , calcSumByteAddOnes(data, len, mask) + , calcSumNibbleAddOnes(data, len, mask) + , calcSumCrumbAddOnes(data, len, mask) + , calcSumByteSubOnes(data, len, mask) + , calcSumNibbleSubOnes(data, len, mask) + , calcSumByteXor(data, len, mask) + , calcSumNibbleXor(data, len, mask) + , calcSumCrumbXor(data, len, mask) + , calcBSDchecksum8(data, len, mask) + , calcBSDchecksum4(data, len, mask) + ); + return 0; } -int CmdAnalyseDates(const char *Cmd){ - // look for datestamps in a given array of bytes - PrintAndLogEx(NORMAL, "To be implemented. Feel free to contribute!"); - return 0; +static int CmdAnalyseDates(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + // look for datestamps in a given array of bytes + PrintAndLogEx(NORMAL, "To be implemented. Feel free to contribute!"); + return 0; } -int CmdAnalyseTEASelfTest(const char *Cmd){ - - uint8_t v[8], v_le[8]; - memset(v, 0x00, sizeof(v)); - memset(v_le, 0x00, sizeof(v_le)); - uint8_t* v_ptr = v_le; +static int CmdAnalyseTEASelfTest(const char *Cmd) { - uint8_t cmdlen = strlen(Cmd); - cmdlen = ( sizeof(v)<<2 < cmdlen ) ? sizeof(v)<<2 : cmdlen; - - if ( param_gethex(Cmd, 0, v, cmdlen) > 0 ){ - PrintAndLogEx(WARNING, "Can't read hex chars, uneven? :: %u", cmdlen); - return 1; - } - - SwapEndian64ex(v , 8, 4, v_ptr); - - // ENCRYPTION KEY: - uint8_t key[16] = {0x55,0xFE,0xF6,0x30,0x62,0xBF,0x0B,0xC1,0xC9,0xB3,0x7C,0x34,0x97,0x3E,0x29,0xFB }; - uint8_t keyle[16]; - uint8_t* key_ptr = keyle; - SwapEndian64ex(key , sizeof(key), 4, key_ptr); - - PrintAndLogEx(NORMAL, "TEST LE enc| %s", sprint_hex(v_ptr, 8)); - - tea_decrypt(v_ptr, key_ptr); - PrintAndLogEx(NORMAL, "TEST LE dec | %s", sprint_hex_ascii(v_ptr, 8)); - - tea_encrypt(v_ptr, key_ptr); - tea_encrypt(v_ptr, key_ptr); - PrintAndLogEx(NORMAL, "TEST enc2 | %s", sprint_hex_ascii(v_ptr, 8)); + uint8_t v[8], v_le[8]; + memset(v, 0x00, sizeof(v)); + memset(v_le, 0x00, sizeof(v_le)); + uint8_t *v_ptr = v_le; - return 0; + uint8_t cmdlen = strlen(Cmd); + cmdlen = (sizeof(v) << 2 < cmdlen) ? sizeof(v) << 2 : cmdlen; + + if (param_gethex(Cmd, 0, v, cmdlen) > 0) { + PrintAndLogEx(WARNING, "Can't read hex chars, uneven? :: %u", cmdlen); + return 1; + } + + SwapEndian64ex(v, 8, 4, v_ptr); + + // ENCRYPTION KEY: + uint8_t key[16] = {0x55, 0xFE, 0xF6, 0x30, 0x62, 0xBF, 0x0B, 0xC1, 0xC9, 0xB3, 0x7C, 0x34, 0x97, 0x3E, 0x29, 0xFB }; + uint8_t keyle[16]; + uint8_t *key_ptr = keyle; + SwapEndian64ex(key, sizeof(key), 4, key_ptr); + + PrintAndLogEx(NORMAL, "TEST LE enc| %s", sprint_hex(v_ptr, 8)); + + tea_decrypt(v_ptr, key_ptr); + PrintAndLogEx(NORMAL, "TEST LE dec | %s", sprint_hex_ascii(v_ptr, 8)); + + tea_encrypt(v_ptr, key_ptr); + tea_encrypt(v_ptr, key_ptr); + PrintAndLogEx(NORMAL, "TEST enc2 | %s", sprint_hex_ascii(v_ptr, 8)); + + return 0; } -char* pb(uint32_t b) { - static char buf1[33] = {0}; - static char buf2[33] = {0}; - static char *s; - - if (s != buf1) - s = buf1; - else - s = buf2; - - memset(s, 0, sizeof(buf1)); - - uint32_t mask = 0x80000000; - for (uint8_t i=0; i<32;i++) { - s[i] = (mask & b)?'1':'0'; - mask >>= 1; - } - return s; -} - -int CmdAnalyseA(const char *Cmd){ - - int hexlen = 0; - uint8_t cmdp = 0; - bool errors = false; - uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'd': - param_gethex_ex(Cmd, cmdp+1, data, &hexlen); - hexlen >>= 1; - if ( hexlen != sizeof(data) ) { - PrintAndLogEx(WARNING, "Read %d bytes of %u", hexlen, sizeof(data) ); - } - cmdp += 2; - break; - case 'h': - return usage_analyse_a(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0 ) return usage_analyse_a(); - - - UsbCommand c = {CMD_FPC_SEND, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - return 1; - } - PrintAndLogEx(NORMAL, "got ack"); - return 0; - - PrintAndLogEx(NORMAL, "-- " _BLUE_(its my message) "\n"); - PrintAndLogEx(NORMAL, "-- " _RED_(its my message) "\n"); - PrintAndLogEx(NORMAL, "-- " _YELLOW_(its my message) "\n"); - PrintAndLogEx(NORMAL, "-- " _GREEN_(its my message) "\n"); - - //uint8_t syncBit = 99; - // 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 ...xx1111 11111111 00x11111xxxxxx... pattern - // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) - # define SYNC_16BIT 0xB24D - uint32_t shiftReg = param_get32ex(Cmd, 0, 0xb24d, 16); - uint8_t bt = param_get8ex(Cmd, 1, 0xBB, 16); - uint8_t byte_offset = 99; - // reverse byte - uint8_t rev = reflect8(bt); - PrintAndLogEx(NORMAL, "input %02x | %02x \n", bt, rev); - // add byte to shift register - shiftReg = shiftReg << 8 | rev; - - PrintAndLogEx(NORMAL, "shiftreg after %08x | pattern %08x \n", shiftReg, SYNC_16BIT); - - uint8_t n0 = 0, n1 = 0; - - n0 = (rev & (uint8_t)(~(0xFF >> (8-4)))) >> 4; - n1 = (n1 << 4) | (rev & (uint8_t)(~(0xFF << 4))); - - PrintAndLogEx(NORMAL, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1) ); - /* -hex(0xb24d shr 0) 0xB24D 0b1011001001001101 -hex(0xb24d shr 1) 0x5926 -hex(0xb24d shr 2) 0x2C93 -*/ +static char *pb(uint32_t b) { + static char buf1[33] = {0}; + static char buf2[33] = {0}; + static char *s; -for ( int i =0; i< 16; i++) { - PrintAndLogEx(NORMAL, " (shiftReg >> %d) & 0xFFFF == %08x ---", i, (( shiftReg >> i) & 0xFFFF )); + if (s != buf1) + s = buf1; + else + s = buf2; - // kolla om SYNC_PATTERN finns. - if ((( shiftReg >> 7) & 0xFFFF ) == SYNC_16BIT) byte_offset = 7; - else if ((( shiftReg >> 6) & 0xFFFF ) == SYNC_16BIT) byte_offset = 6; - else if ((( shiftReg >> 5) & 0xFFFF ) == SYNC_16BIT) byte_offset = 5; - else if ((( shiftReg >> 4) & 0xFFFF ) == SYNC_16BIT) byte_offset = 4; - else if ((( shiftReg >> 3) & 0xFFFF ) == SYNC_16BIT) byte_offset = 3; - else if ((( shiftReg >> 2) & 0xFFFF ) == SYNC_16BIT) byte_offset = 2; - else if ((( shiftReg >> 1) & 0xFFFF ) == SYNC_16BIT) byte_offset = 1; - else if ((( shiftReg >> 0) & 0xFFFF ) == SYNC_16BIT) byte_offset = 0; + memset(s, 0, sizeof(buf1)); - PrintAndLogEx(NORMAL, "Offset %u \n", byte_offset); - if ( byte_offset != 99 ) - break; - - shiftReg >>=1; + uint32_t mask = 0x80000000; + for (uint8_t i = 0; i < 32; i++) { + s[i] = (mask & b) ? '1' : '0'; + mask >>= 1; + } + return s; } - - uint8_t p1 = (rev & (uint8_t)(~(0xFF << byte_offset))); - PrintAndLogEx(NORMAL, "Offset %u | leftovers %02x %s \n", byte_offset, p1, pb(p1) ); - - - - /* -pm3 --> da hex2bin 4db2 0100110110110010 */ - return 0; -/* - // split byte into two parts. - uint8_t offset = 3, n0 = 0, n1 = 0; - rev = 0xB2; - for (uint8_t m=0; m<8; m++) { - offset = m; - n0 = (rev & (uint8_t)(~(0xFF >> (8-offset)))) >> offset; - n1 = (n1 << offset) | (rev & (uint8_t)(~(0xFF << offset))); - PrintAndLogEx(NORMAL, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1) ); - n0 = 0, n1 = 0; - // PrintAndLogEx(NORMAL, " (0xFF >> offset) == %s |\n", pb( (0xFF >> offset)) ); - //PrintAndLogEx(NORMAL, "~(0xFF >> (8-offset)) == %s |\n", pb( (uint8_t)(~(0xFF >> (8-offset))) ) ); - //PrintAndLogEx(NORMAL, " rev & xxx == %s\n\n", pb( (rev & (uint8_t)(~(0xFF << offset))) )); - } -return 0; - // from A -- x bits into B and the rest into C. - - for ( uint8_t i=0; i<8; i++){ - PrintAndLogEx(NORMAL, "%u | %02X %s | %02X %s |\n", i, a, pb(a), b, pb(b) ); - b = a & (a & (0xFF >> (8-i))); - a >>=1; - } - - */ - return 0; +static int CmdAnalyseA(const char *Cmd) { - // 14443-A - uint8_t u14_c[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe8 }; // atqs w crc - uint8_t u14_w[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe7 }; // atqs w crc - PrintAndLogEx(FAILED, "14a check wrong crc | %s\n", (check_crc(CRC_14443_A, u14_w, sizeof(u14_w))) ? "YES": "NO" ); - PrintAndLogEx(SUCCESS, "14a check correct crc | %s\n", (check_crc(CRC_14443_A, u14_c, sizeof(u14_c))) ? "YES": "NO" ); - - // 14443-B - uint8_t u14b[] = {0x05,0x00,0x08,0x39,0x73}; - PrintAndLogEx(NORMAL, "14b check crc | %s\n", (check_crc(CRC_14443_B, u14b, sizeof(u14b))) ? "YES": "NO"); + return usage_analyse_a(); + /* + PrintAndLogEx(NORMAL, "-- " _BLUE_("its my message") "\n"); + PrintAndLogEx(NORMAL, "-- " _RED_("its my message") "\n"); + PrintAndLogEx(NORMAL, "-- " _YELLOW_("its my message") "\n"); + PrintAndLogEx(NORMAL, "-- " _GREEN_("its my message") "\n"); - // 15693 test - uint8_t u15_c[] = {0x05,0x00,0x08,0x39,0x73}; // correct - uint8_t u15_w[] = {0x05,0x00,0x08,0x39,0x72}; // wrong - PrintAndLogEx(FAILED, "15 check wrong crc | %s\n", (check_crc(CRC_15693, u15_w, sizeof(u15_w))) ? "YES": "NO"); - PrintAndLogEx(SUCCESS, "15 check correct crc | %s\n", (check_crc(CRC_15693, u15_c, sizeof(u15_c))) ? "YES": "NO"); + //uint8_t syncBit = 99; + // 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 ...xx1111 11111111 00x11111xxxxxx... pattern + // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) + # define SYNC_16BIT 0xB24D + uint32_t shiftReg = param_get32ex(Cmd, 0, 0xb24d, 16); + uint8_t bt = param_get8ex(Cmd, 1, 0xBB, 16); + uint8_t byte_offset = 99; + // reverse byte + uint8_t rev = reflect8(bt); + PrintAndLogEx(NORMAL, "input %02x | %02x \n", bt, rev); + // add byte to shift register + shiftReg = shiftReg << 8 | rev; - // iCLASS test - wrong crc , swapped bytes. - uint8_t iclass_w[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x01, 0x43}; - uint8_t iclass_c[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01}; - PrintAndLogEx(FAILED, "iCLASS check wrong crc | %s\n", (check_crc(CRC_ICLASS, iclass_w, sizeof(iclass_w))) ? "YES": "NO"); - PrintAndLogEx(SUCCESS, "iCLASS check correct crc | %s\n", (check_crc(CRC_ICLASS, iclass_c, sizeof(iclass_c))) ? "YES": "NO"); - - // FeliCa test - uint8_t felica_w[] = {0x12,0x01,0x01,0x2e,0x3d,0x17,0x26,0x47,0x80, 0x95,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7e}; - uint8_t felica_c[] = {0x12,0x01,0x01,0x2e,0x3d,0x17,0x26,0x47,0x80, 0x95,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f}; - PrintAndLogEx(FAILED, "FeliCa check wrong crc | %s\n", (check_crc(CRC_FELICA, felica_w, sizeof(felica_w))) ? "YES": "NO"); - PrintAndLogEx(SUCCESS, "FeliCa check correct crc | %s\n", (check_crc(CRC_FELICA, felica_c, sizeof(felica_c))) ? "YES": "NO"); - - PrintAndLogEx(NORMAL, "\n\n"); + PrintAndLogEx(NORMAL, "shiftreg after %08x | pattern %08x \n", shiftReg, SYNC_16BIT); + + uint8_t n0 = 0, n1 = 0; + + n0 = (rev & (uint8_t)(~(0xFF >> (8 - 4)))) >> 4; + n1 = (n1 << 4) | (rev & (uint8_t)(~(0xFF << 4))); + + PrintAndLogEx(NORMAL, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1)); + */ + /* + hex(0xb24d shr 0) 0xB24D 0b1011001001001101 + hex(0xb24d shr 1) 0x5926 + hex(0xb24d shr 2) 0x2C93 + */ + + /* + for (int i = 0; i < 16; i++) { + PrintAndLogEx(NORMAL, " (shiftReg >> %d) & 0xFFFF == %08x ---", i, ((shiftReg >> i) & 0xFFFF)); + + // kolla om SYNC_PATTERN finns. + if (((shiftReg >> 7) & 0xFFFF) == SYNC_16BIT) byte_offset = 7; + else if (((shiftReg >> 6) & 0xFFFF) == SYNC_16BIT) byte_offset = 6; + else if (((shiftReg >> 5) & 0xFFFF) == SYNC_16BIT) byte_offset = 5; + else if (((shiftReg >> 4) & 0xFFFF) == SYNC_16BIT) byte_offset = 4; + else if (((shiftReg >> 3) & 0xFFFF) == SYNC_16BIT) byte_offset = 3; + else if (((shiftReg >> 2) & 0xFFFF) == SYNC_16BIT) byte_offset = 2; + else if (((shiftReg >> 1) & 0xFFFF) == SYNC_16BIT) byte_offset = 1; + else if (((shiftReg >> 0) & 0xFFFF) == SYNC_16BIT) byte_offset = 0; + + PrintAndLogEx(NORMAL, "Offset %u \n", byte_offset); + if (byte_offset != 99) + break; + + shiftReg >>= 1; + } + + uint8_t p1 = (rev & (uint8_t)(~(0xFF << byte_offset))); + PrintAndLogEx(NORMAL, "Offset %u | leftovers %02x %s \n", byte_offset, p1, pb(p1)); + + */ + + /* + pm3 --> da hex2bin 4db2 0100110110110010 + */ + //return 0; + /* + // split byte into two parts. + uint8_t offset = 3, n0 = 0, n1 = 0; + rev = 0xB2; + for (uint8_t m=0; m<8; m++) { + offset = m; + n0 = (rev & (uint8_t)(~(0xFF >> (8-offset)))) >> offset; + n1 = (n1 << offset) | (rev & (uint8_t)(~(0xFF << offset))); + + PrintAndLogEx(NORMAL, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1) ); + n0 = 0, n1 = 0; + // PrintAndLogEx(NORMAL, " (0xFF >> offset) == %s |\n", pb( (0xFF >> offset)) ); + //PrintAndLogEx(NORMAL, "~(0xFF >> (8-offset)) == %s |\n", pb( (uint8_t)(~(0xFF >> (8-offset))) ) ); + //PrintAndLogEx(NORMAL, " rev & xxx == %s\n\n", pb( (rev & (uint8_t)(~(0xFF << offset))) )); + } + return 0; + // from A -- x bits into B and the rest into C. + + for ( uint8_t i=0; i<8; i++){ + PrintAndLogEx(NORMAL, "%u | %02X %s | %02X %s |\n", i, a, pb(a), b, pb(b) ); + b = a & (a & (0xFF >> (8-i))); + a >>=1; + } + + */ +// return 0; + + /* + // 14443-A + uint8_t u14_c[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe8 }; // atqs w crc + uint8_t u14_w[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe7 }; // atqs w crc + PrintAndLogEx(FAILED, "14a check wrong crc | %s\n", (check_crc(CRC_14443_A, u14_w, sizeof(u14_w))) ? "YES" : "NO"); + PrintAndLogEx(SUCCESS, "14a check correct crc | %s\n", (check_crc(CRC_14443_A, u14_c, sizeof(u14_c))) ? "YES" : "NO"); + + // 14443-B + uint8_t u14b[] = {0x05, 0x00, 0x08, 0x39, 0x73}; + PrintAndLogEx(NORMAL, "14b check crc | %s\n", (check_crc(CRC_14443_B, u14b, sizeof(u14b))) ? "YES" : "NO"); + + // 15693 test + uint8_t u15_c[] = {0x05, 0x00, 0x08, 0x39, 0x73}; // correct + uint8_t u15_w[] = {0x05, 0x00, 0x08, 0x39, 0x72}; // wrong + PrintAndLogEx(FAILED, "15 check wrong crc | %s\n", (check_crc(CRC_15693, u15_w, sizeof(u15_w))) ? "YES" : "NO"); + PrintAndLogEx(SUCCESS, "15 check correct crc | %s\n", (check_crc(CRC_15693, u15_c, sizeof(u15_c))) ? "YES" : "NO"); + + // iCLASS test - wrong crc , swapped bytes. + uint8_t iclass_w[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x01, 0x43}; + uint8_t iclass_c[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01}; + PrintAndLogEx(FAILED, "iCLASS check wrong crc | %s\n", (check_crc(CRC_ICLASS, iclass_w, sizeof(iclass_w))) ? "YES" : "NO"); + PrintAndLogEx(SUCCESS, "iCLASS check correct crc | %s\n", (check_crc(CRC_ICLASS, iclass_c, sizeof(iclass_c))) ? "YES" : "NO"); + + // FeliCa test + uint8_t felica_w[] = {0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7e}; + uint8_t felica_c[] = {0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f}; + PrintAndLogEx(FAILED, "FeliCa check wrong crc | %s\n", (check_crc(CRC_FELICA, felica_w, sizeof(felica_w))) ? "YES" : "NO"); + PrintAndLogEx(SUCCESS, "FeliCa check correct crc | %s\n", (check_crc(CRC_FELICA, felica_c, sizeof(felica_c))) ? "YES" : "NO"); + + PrintAndLogEx(NORMAL, "\n\n"); + + return 0; + */ + /* + bool term = !isatty(STDIN_FILENO); + if (!term) { + char star[4]; + star[0] = '-'; + star[1] = '\\'; + star[2] = '|'; + star[3] = '/'; + + for (uint8_t k=0; k<4; k = (k+1) % 4 ) { + PrintAndLogEx(NORMAL, "\e[s%c\e[u", star[k]); + fflush(stdout); + if (ukbhit()) { + int gc = getchar(); (void)gc; + break; + } + } + } + */ - return 0; - /* - bool term = !isatty(STDIN_FILENO); - if (!term) { - char star[4]; - star[0] = '-'; - star[1] = '\\'; - star[2] = '|'; - star[3] = '/'; - - for (uint8_t k=0; k<4; k = (k+1) % 4 ) { - PrintAndLogEx(NORMAL, "\e[s%c\e[u", star[k]); - fflush(stdout); - if (ukbhit()) { - int gc = getchar(); (void)gc; - break; - } - } - } - */ - //piwi // uid(2e086b1a) nt(230736f6) ks(0b0008000804000e) nr(000000000) // uid(2e086b1a) nt(230736f6) ks(0e0b0e0b090c0d02) nr(000000001) // uid(2e086b1a) nt(230736f6) ks(0e05060e01080b08) nr(000000002) //uint64_t d1[] = {0x2e086b1a, 0x230736f6, 0x0000001, 0x0e0b0e0b090c0d02}; //uint64_t d2[] = {0x2e086b1a, 0x230736f6, 0x0000002, 0x0e05060e01080b08}; - + // uid(17758822) nt(c0c69e59) ks(080105020705040e) nr(00000001) // uid(17758822) nt(c0c69e59) ks(01070a05050c0705) nr(00000002) //uint64_t d1[] = {0x17758822, 0xc0c69e59, 0x0000001, 0x080105020705040e}; //uint64_t d2[] = {0x17758822, 0xc0c69e59, 0x0000002, 0x01070a05050c0705}; - + // uid(6e442129) nt(8f699195) ks(090d0b0305020f02) nr(00000001) // uid(6e442129) nt(8f699195) ks(03030508030b0c0e) nr(00000002) // uid(6e442129) nt(8f699195) ks(02010f030c0d050d) nr(00000003) @@ -686,229 +650,242 @@ return 0; //uint64_t d1[] = {0x6e442129, 0x8f699195, 0x0000001, 0x090d0b0305020f02}; //uint64_t d2[] = {0x6e442129, 0x8f699195, 0x0000004, 0x00040f0f0305030e}; -/* -uid(3e172b29) nt(039b7bd2) ks(0c0e0f0505080800) nr(00000001) -uid(3e172b29) nt(039b7bd2) ks(0e06090d03000b0f) nr(00000002) -*/ - uint64_t *keylistA = NULL, *keylistB = NULL; - uint32_t keycountA = 0, keycountB = 0; -// uint64_t d1[] = {0x3e172b29, 0x039b7bd2, 0x0000001, 0, 0x0c0e0f0505080800}; -// uint64_t d2[] = {0x3e172b29, 0x039b7bd2, 0x0000002, 0, 0x0e06090d03000b0f}; -uint64_t d1[] = {0x6e442129, 0x8f699195, 0x0000001, 0, 0x090d0b0305020f02}; -uint64_t d2[] = {0x6e442129, 0x8f699195, 0x0000004, 0, 0x00040f0f0305030e}; - - keycountA = nonce2key(d1[0], d1[1], d1[2], 0, d1[3], d1[4] ,&keylistA); - keycountB = nonce2key(d2[0], d2[1], d2[2], 0, d2[3], d2[4], &keylistB); + /* + uid(3e172b29) nt(039b7bd2) ks(0c0e0f0505080800) nr(00000001) + uid(3e172b29) nt(039b7bd2) ks(0e06090d03000b0f) nr(00000002) + */ + /* + uint64_t *keylistA = NULL, *keylistB = NULL; + uint32_t keycountA = 0, keycountB = 0; + // uint64_t d1[] = {0x3e172b29, 0x039b7bd2, 0x0000001, 0, 0x0c0e0f0505080800}; + // uint64_t d2[] = {0x3e172b29, 0x039b7bd2, 0x0000002, 0, 0x0e06090d03000b0f}; + uint64_t d1[] = {0x6e442129, 0x8f699195, 0x0000001, 0, 0x090d0b0305020f02}; + uint64_t d2[] = {0x6e442129, 0x8f699195, 0x0000004, 0, 0x00040f0f0305030e}; - switch (keycountA) { - case 0: PrintAndLogEx(FAILED, "Key test A failed\n"); break; - case 1: PrintAndLogEx(SUCCESS, "KEY A | %012" PRIX64 " ", keylistA[0]); break; - } - switch (keycountB) { - case 0: PrintAndLogEx(FAILED, "Key test B failed\n"); break; - case 1: PrintAndLogEx(SUCCESS, "KEY B | %012" PRIX64 " ", keylistB[0]); break; - } - - free(keylistA); - free(keylistB); - -// qsort(keylist, keycount, sizeof(*keylist), compare_uint64); -// keycount = intersection(last_keylist, keylist); + keycountA = nonce2key(d1[0], d1[1], d1[2], 0, d1[3], d1[4], &keylistA); + keycountB = nonce2key(d2[0], d2[1], d2[2], 0, d2[3], d2[4], &keylistB); - /* - uint64_t keys[] = { - 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961, - 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3, - 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c, - 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9, - 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a, - 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba, - 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b, - 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe - }; - - uint64_t keya[] = { - 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961, - 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3, - 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c, - 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9 - }; - uint64_t keyb[] = { - 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a, - 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba, - 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b, - 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe - }; - - */ - - /* - uint64_t xor[] = { - 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B, - 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6, - 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52, - 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC, 0xB6E97F5F6776, - 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F, - 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD, - 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8, - 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244 - }; - + switch (keycountA) { + case 0: + PrintAndLogEx(FAILED, "Key test A failed\n"); + break; + case 1: + PrintAndLogEx(SUCCESS, "KEY A | %012" PRIX64 " ", keylistA[0]); + break; + } + switch (keycountB) { + case 0: + PrintAndLogEx(FAILED, "Key test B failed\n"); + break; + case 1: + PrintAndLogEx(SUCCESS, "KEY B | %012" PRIX64 " ", keylistB[0]); + break; + } - uint64_t xorA[] = { - 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B, - 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6, - 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52, - 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC - }; - uint64_t xorB[] = { - 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F, - 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD, - 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8, - 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244 - }; - */ - /* - // xor key A | xor key B - 1 | 0DEFED88E531 | 2F87A1BDC230 - 2 | 7577AFA2E1BC | E43F502B984C - 3 | 14D7D7BDBEC3 | 8A776AB752D9 - 4 | F5ABD3C6278B | 9A58D96A472F - 5 | AABDFA08276F | EF3702E01916 - 6 | B77C275C10D6 | 48A03B01D007 - 7 | B6DD0B434080 | 14754B0D659E - 8 | AAF2444499C6 | 009AD1868FDD - 9 | 852D7F8EBF90 | 6082DB527C11 - 10 | 3108821DB92C | 4D666ADA4C0E - 11 | B3756A1FB685 | 2D461D05F163 - 12 | DFE627C86A52 | 3596CFF0FEC8 - 13 | 5D3C093EF375 | 8CBD9258FE22 - 14 | 28C81D6FBF0E | 00D29A7B304B - 15 | 1204DF4D3ECC | BC33DC6C9244 - */ + free(keylistA); + free(keylistB); + */ +// qsort(keylist, keycount, sizeof(*keylist), compare_uint64); +// keycount = intersection(last_keylist, keylist); - // generate xor table :) - /* - for (uint8_t i=0; i<31; i++){ - uint64_t a = keys[i] ^ keys[i+1]; - PrintAndLogEx(NORMAL, "%u | %012" PRIX64 " | \n", i, a); - } - */ - - /* - uint32_t id = param_get32ex(Cmd, 0, 0x93290142, 16); - uint8_t uid[6] = {0}; - num_to_bytes(id,4,uid); - - uint8_t key_s0a[] = { - uid[1] ^ uid[2] ^ uid[3] ^ 0x11, - uid[1] ^ 0x72, - uid[2] ^ 0x80, - (uid[0] + uid[1] + uid[2] + uid[3] ) ^ uid[3] ^ 0x19, - 0xA3, - 0x2F - }; + /* + uint64_t keys[] = { + 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961, + 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3, + 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c, + 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9, + 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a, + 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba, + 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b, + 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe + }; - PrintAndLogEx(NORMAL, "UID | %s\n", sprint_hex(uid,4 )); - PrintAndLogEx(NORMAL, "KEY A | %s\n", sprint_hex(key_s0a, 6)); - - // arrays w all keys - uint64_t foo[32] = {0}; - - //A - foo[0] = bytes_to_num(key_s0a, 6); - //B - //foo[16] = 0xcafe71411fbf; - foo[16] = 0xeafe51411fbf; - - for (uint8_t i=0; i<15; i++){ - foo[i+1] = foo[i] ^ xorA[i]; - foo[i+16+1] = foo[i+16] ^ xorB[i]; - - } - for (uint8_t i=0; i<15; i++){ - uint64_t a = foo[i]; - uint64_t b = foo[i+16]; + uint64_t keya[] = { + 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961, + 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3, + 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c, + 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9 + }; + uint64_t keyb[] = { + 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a, + 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba, + 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b, + 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe + }; - PrintAndLogEx(NORMAL, "%02u | %012" PRIX64 " %s | %012" PRIX64 " %s\n", - i, - a, - ( a == keya[i])?"ok":"err", - b, - ( b == keyb[i])?"ok":"err" - ); - } - */ - return 0; + */ + + /* + uint64_t xor[] = { + 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B, + 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6, + 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52, + 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC, 0xB6E97F5F6776, + 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F, + 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD, + 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8, + 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244 + }; + + + uint64_t xorA[] = { + 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B, + 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6, + 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52, + 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC + }; + uint64_t xorB[] = { + 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F, + 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD, + 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8, + 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244 + }; + */ + /* + // xor key A | xor key B + 1 | 0DEFED88E531 | 2F87A1BDC230 + 2 | 7577AFA2E1BC | E43F502B984C + 3 | 14D7D7BDBEC3 | 8A776AB752D9 + 4 | F5ABD3C6278B | 9A58D96A472F + 5 | AABDFA08276F | EF3702E01916 + 6 | B77C275C10D6 | 48A03B01D007 + 7 | B6DD0B434080 | 14754B0D659E + 8 | AAF2444499C6 | 009AD1868FDD + 9 | 852D7F8EBF90 | 6082DB527C11 + 10 | 3108821DB92C | 4D666ADA4C0E + 11 | B3756A1FB685 | 2D461D05F163 + 12 | DFE627C86A52 | 3596CFF0FEC8 + 13 | 5D3C093EF375 | 8CBD9258FE22 + 14 | 28C81D6FBF0E | 00D29A7B304B + 15 | 1204DF4D3ECC | BC33DC6C9244 + */ + + // generate xor table :) + /* + for (uint8_t i=0; i<31; i++){ + uint64_t a = keys[i] ^ keys[i+1]; + PrintAndLogEx(NORMAL, "%u | %012" PRIX64 " | \n", i, a); + } + */ + + /* + uint32_t id = param_get32ex(Cmd, 0, 0x93290142, 16); + uint8_t uid[6] = {0}; + num_to_bytes(id,4,uid); + + uint8_t key_s0a[] = { + uid[1] ^ uid[2] ^ uid[3] ^ 0x11, + uid[1] ^ 0x72, + uid[2] ^ 0x80, + (uid[0] + uid[1] + uid[2] + uid[3] ) ^ uid[3] ^ 0x19, + 0xA3, + 0x2F + }; + + PrintAndLogEx(NORMAL, "UID | %s\n", sprint_hex(uid,4 )); + PrintAndLogEx(NORMAL, "KEY A | %s\n", sprint_hex(key_s0a, 6)); + + // arrays w all keys + uint64_t foo[32] = {0}; + + //A + foo[0] = bytes_to_num(key_s0a, 6); + //B + //foo[16] = 0xcafe71411fbf; + foo[16] = 0xeafe51411fbf; + + for (uint8_t i=0; i<15; i++){ + foo[i+1] = foo[i] ^ xorA[i]; + foo[i+16+1] = foo[i+16] ^ xorB[i]; + + } + for (uint8_t i=0; i<15; i++){ + uint64_t a = foo[i]; + uint64_t b = foo[i+16]; + + PrintAndLogEx(NORMAL, "%02u | %012" PRIX64 " %s | %012" PRIX64 " %s\n", + i, + a, + ( a == keya[i])?"ok":"err", + b, + ( b == keyb[i])?"ok":"err" + ); + } + */ +// return 0; } -void generate4bNUID(uint8_t *uid, uint8_t *nuid){ - uint16_t crc; - uint8_t b1, b2; - - compute_crc(CRC_14443_A, uid, 3, &b1, &b2); - nuid[0] |= (b2 & 0xE0) | 0xF; - nuid[1] = b1; - - crc = b1; - crc |= b2 << 8; - - crc = update_crc16(uid[3], crc); - crc = update_crc16(uid[4], crc); - crc = update_crc16(uid[5], crc); - crc = update_crc16(uid[6], crc); - - nuid[2] = (crc >> 8) & 0xFF ; - nuid[3] = crc & 0xFF; +static void generate4bNUID(uint8_t *uid, uint8_t *nuid) { + uint16_t crc; + uint8_t b1, b2; + + compute_crc(CRC_14443_A, uid, 3, &b1, &b2); + nuid[0] = (b2 & 0xE0) | 0xF; + nuid[1] = b1; + crc = b1; + crc |= b2 << 8; + crc = crc16_fast(&uid[3], 4, reflect16(crc), true, true); + nuid[2] = (crc >> 8) & 0xFF ; + nuid[3] = crc & 0xFF; } -int CmdAnalyseNuid(const char *Cmd){ - uint8_t nuid[4] = {0}; - uint8_t uid[7] = {0}; - int len = 0; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) == 0|| cmdp == 'h' || cmdp == 'H') return usage_analyse_nuid(); +static int CmdAnalyseNuid(const char *Cmd) { + uint8_t nuid[4] = {0}; + uint8_t uid[7] = {0}; + int len = 0; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_analyse_nuid(); - /* selftest UID 040D681AB52281 -> NUID 8F430FEF */ - if (cmdp == 't' || cmdp == 'T') { - memcpy(uid, "\x04\x0d\x68\x1a\xb5\x22\x81", 7); - generate4bNUID(uid, nuid); - if ( 0 == memcmp(nuid, "\x8f\x43\x0f\xef", 4)) - PrintAndLogEx(SUCCESS, "Selftest OK\n"); - else - PrintAndLogEx(FAILED, "Selftest Failed\n"); - return 0; - } + /* src: https://www.nxp.com/docs/en/application-note/AN10927.pdf */ + /* selftest1 UID 040D681AB52281 -> NUID 8F430FEF */ + /* selftest2 UID 04183F09321B85 -> NUID 4F505D7D */ + if (cmdp == 't') { + uint8_t uid_test1[] = {0x04, 0x0d, 0x68, 0x1a, 0xb5, 0x22, 0x81}; + uint8_t nuid_test1[] = {0x8f, 0x43, 0x0f, 0xef}; + uint8_t uid_test2[] = {0x04, 0x18, 0x3f, 0x09, 0x32, 0x1b, 0x85}; + uint8_t nuid_test2[] = {0x4f, 0x50, 0x5d, 0x7d}; + memcpy(uid, uid_test1, sizeof(uid)); + generate4bNUID(uid, nuid); - param_gethex_ex(Cmd, 0, uid, &len); - if ( len%2 || len != 14) return usage_analyse_nuid(); + bool test1 = (0 == memcmp(nuid, nuid_test1, sizeof(nuid))); + PrintAndLogEx(SUCCESS, "Selftest1 %s\n", test1 ? _GREEN_("OK") : _RED_("Fail")); - generate4bNUID(uid, nuid); - - PrintAndLogEx(NORMAL, "UID | %s \n", sprint_hex(uid, 7)); - PrintAndLogEx(NORMAL, "NUID | %s \n", sprint_hex(nuid, 4)); - return 0; + memcpy(uid, uid_test2, sizeof(uid)); + generate4bNUID(uid, nuid); + bool test2 = (0 == memcmp(nuid, nuid_test2, sizeof(nuid))); + PrintAndLogEx(SUCCESS, "Selftest2 %s\n", test2 ? _GREEN_("OK") : _RED_("Fail")); + return 0; + } + + param_gethex_ex(Cmd, 0, uid, &len); + if (len % 2 || len != 14) return usage_analyse_nuid(); + + generate4bNUID(uid, nuid); + + PrintAndLogEx(NORMAL, "UID | %s \n", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL, "NUID | %s \n", sprint_hex(nuid, 4)); + return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"lcr", CmdAnalyseLCR, 1, "Generate final byte for XOR LRC"}, - {"crc", CmdAnalyseCRC, 1, "Stub method for CRC evaluations"}, - {"chksum", CmdAnalyseCHKSUM, 1, "Checksum with adding, masking and one's complement"}, - {"dates", CmdAnalyseDates, 1, "Look for datestamps in a given array of bytes"}, - {"tea", CmdAnalyseTEASelfTest, 1, "Crypto TEA test"}, - {"lfsr", CmdAnalyseLfsr, 1, "LFSR tests"}, - {"a", CmdAnalyseA, 1, "num bits test"}, - {"nuid", CmdAnalyseNuid, 1, "create NUID from 7byte UID"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"lcr", CmdAnalyseLCR, AlwaysAvailable, "Generate final byte for XOR LRC"}, + {"crc", CmdAnalyseCRC, AlwaysAvailable, "Stub method for CRC evaluations"}, + {"chksum", CmdAnalyseCHKSUM, AlwaysAvailable, "Checksum with adding, masking and one's complement"}, + {"dates", CmdAnalyseDates, AlwaysAvailable, "Look for datestamps in a given array of bytes"}, + {"tea", CmdAnalyseTEASelfTest, AlwaysAvailable, "Crypto TEA test"}, + {"lfsr", CmdAnalyseLfsr, AlwaysAvailable, "LFSR tests"}, + {"a", CmdAnalyseA, AlwaysAvailable, "num bits test"}, + {"nuid", CmdAnalyseNuid, AlwaysAvailable, "create NUID from 7byte UID"}, + {NULL, NULL, NULL, NULL} }; -int CmdAnalyse(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +int CmdAnalyse(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } diff --git a/client/cmdanalyse.h b/client/cmdanalyse.h index f834c717d..20dc58a7e 100644 --- a/client/cmdanalyse.h +++ b/client/cmdanalyse.h @@ -11,35 +11,20 @@ #ifndef CMDANALYSE_H__ #define CMDANALYSE_H__ -#include //size_t +#include // size_t #include #include #include "cmdmain.h" #include "proxmark3.h" -#include "ui.h" // PrintAndLog +#include "ui.h" // PrintAndLog #include "util.h" #include "crc.h" -#include "crc16.h" // crc16 ccitt +#include "crc16.h" // crc16 ccitt #include "tea.h" #include "legic_prng.h" #include "loclass/elite_crack.h" -#include "mfkey.h" //nonce2key -#include "util_posix.h" // msclock - - -int usage_analyse_lcr(void); -int usage_analyse_checksum(void); -int usage_analyse_crc(void); -int usage_analyse_hid(void); -int usage_analyse_nuid(void); +#include "mifare/mfkey.h" // nonce2key +#include "util_posix.h" // msclock int CmdAnalyse(const char *Cmd); -int CmdAnalyseLCR(const char *Cmd); -int CmdAnalyseCHKSUM(const char *Cmd); -int CmdAnalyseDates(const char *Cmd); -int CmdAnalyseCRC(const char *Cmd); -int CmdAnalyseTEASelfTest(const char *Cmd); -int CmdAnalyseLfsr(const char *Cmd); -int CmdAnalyseHid(const char *Cmd); -int CmdAnalyseNuid(const char *Cmd); #endif diff --git a/client/cmdcrc.c b/client/cmdcrc.c index 25653dbab..58cab45e5 100644 --- a/client/cmdcrc.c +++ b/client/cmdcrc.c @@ -11,20 +11,18 @@ #define MAX_ARGS 20 -int split(char *str, char *arr[MAX_ARGS]){ +static int split(char *str, char *arr[MAX_ARGS]) { int beginIndex = 0; - int endIndex; - int maxWords = MAX_ARGS; int wordCnt = 0; - while(1){ - while(isspace(str[beginIndex])) { + while (1) { + while (isspace(str[beginIndex])) { ++beginIndex; } - if(str[beginIndex] == '\0') { + if (str[beginIndex] == '\0') { break; - } - endIndex = beginIndex; + } + int endIndex = beginIndex; while (str[endIndex] && !isspace(str[endIndex])) { ++endIndex; } @@ -33,205 +31,194 @@ int split(char *str, char *arr[MAX_ARGS]){ memcpy(tmp, &str[beginIndex], len); arr[wordCnt++] = tmp; beginIndex = endIndex; - if (wordCnt == maxWords) + if (wordCnt == MAX_ARGS) break; } return wordCnt; } -int CmdCrc(const char *Cmd) -{ - char name[] = {"reveng "}; - char Cmd2[100 + 7]; - memcpy(Cmd2, name, 7); - memcpy(Cmd2 + 7, Cmd, 100); - char *argv[MAX_ARGS]; - int argc = split(Cmd2, argv); - - if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) { - CmdrevengSearch(argv[2]); - } else { - reveng_main(argc, argv); - } - for(int i = 0; i < argc; ++i) { - free(argv[i]); - } - return 0; -} - //returns array of model names and the count of models returning // as well as a width array for the width of each model -int GetModels(char *Models[], int *count, uint8_t *width){ - /* default values */ - static model_t model = MZERO; +int GetModels(char *Models[], int *count, uint8_t *width) { + /* default values */ + static model_t model = MZERO; - int ibperhx = 8;//, obperhx = 8; - int rflags = 0, uflags = 0; /* search and UI flags */ - poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL; - model_t pset = model, *candmods, *mptr; + poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL; + model_t pset = model; - /* stdin must be binary */ - #ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); - #endif /* _WIN32 */ + /* stdin must be binary */ +#ifdef _WIN32 + _setmode(STDIN_FILENO, _O_BINARY); +#endif /* _WIN32 */ - SETBMP(); - - int args = 0, psets, pass; - int Cnt = 0; - if (width[0] == 0) { //reveng -D - *count = mcount(); - if (!*count){ - PrintAndLogEx(WARNING, "no preset models available"); - return 0; - } - for (int mode = 0; mode < *count; ++mode) { - mbynum(&model, mode); - mcanon(&model); - size_t size = (model.name && *model.name) ? strlen(model.name) : 7; - char *tmp = calloc(size+1, sizeof(char)); - if (tmp==NULL){ - PrintAndLogEx(WARNING, "out of memory?"); - return 0; - } - memcpy(tmp, model.name, size); - Models[mode] = tmp; - width[mode] = plen(model.spoly); - } - mfree(&model); - } else { //reveng -s + SETBMP(); - if (~model.flags & P_MULXN){ - PrintAndLogEx(WARNING, "cannot search for non-Williams compliant models"); - return 0; - } - praloc(&model.spoly, (unsigned long)width[0]); - praloc(&model.init, (unsigned long)width[0]); - praloc(&model.xorout, (unsigned long)width[0]); + if (width[0] == 0) { //reveng -D + *count = mcount(); + if (!*count) { + PrintAndLogEx(WARNING, "no preset models available"); + return 0; + } + for (int mode = 0; mode < *count; ++mode) { + mbynum(&model, mode); + mcanon(&model); + size_t size = (model.name && *model.name) ? strlen(model.name) : 7; + char *tmp = calloc(size + 1, sizeof(char)); + if (tmp == NULL) { + PrintAndLogEx(WARNING, "out of memory?"); + return 0; + } + if (model.name != NULL) { + memcpy(tmp, model.name, size); + Models[mode] = tmp; + width[mode] = plen(model.spoly); + } + } + mfree(&model); + } else { //reveng -s - if (!plen(model.spoly)) - palloc(&model.spoly, (unsigned long)width[0]); - else - width[0] = (uint8_t)plen(model.spoly); + int ibperhx = 8;//, obperhx = 8; + int rflags = 0, uflags = 0; /* search and UI flags */ + if (~model.flags & P_MULXN) { + PrintAndLogEx(WARNING, "cannot search for non-Williams compliant models"); + return 0; + } + praloc(&model.spoly, (unsigned long)width[0]); + praloc(&model.init, (unsigned long)width[0]); + praloc(&model.xorout, (unsigned long)width[0]); - /* special case if qpoly is zero, search to end of range */ - if (!ptst(qpoly)) - rflags &= ~R_HAVEQ; + if (!plen(model.spoly)) + palloc(&model.spoly, (unsigned long)width[0]); + else + width[0] = (uint8_t)plen(model.spoly); - /* if endianness not specified, try - * little-endian then big-endian. - * NB: crossed-endian algorithms will not be - * searched. - */ - /* scan against preset models */ - if (~uflags & C_NOPCK) { - pass = 0; - Cnt = 0; - do { - psets = mcount(); + /* special case if qpoly is zero, search to end of range */ + if (!ptst(qpoly)) + rflags &= ~R_HAVEQ; - while (psets) { - mbynum(&pset, --psets); - - /* skip if different width, or refin or refout don't match */ - if( plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) - continue; - /* skip if the preset doesn't match specified parameters */ - if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) - continue; - if (rflags & R_HAVEI && psncmp(&model.init, &pset.init)) - continue; - if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) - continue; - - //for additional args (not used yet, maybe future?) - apoly = pclone(pset.xorout); - - if (pset.flags & P_REFOUT) - prev(&apoly); - - - for (qptr = apolys; qptr < pptr; ++qptr) { - crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); - if (ptst(crc)) { - pfree(&crc); - break; - } - pfree(&crc); - } - pfree(&apoly); - - if (qptr == pptr) { + int pass; - /* the selected model solved all arguments */ - mcanon(&pset); - - size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 7; - //PrintAndLogEx(NORMAL, "Size: %d, %s, count: %d",size,pset.name, Cnt); - char *tmp = calloc(size+1, sizeof(char)); - if (tmp == NULL){ - PrintAndLogEx(WARNING, "out of memory?"); - return 0; - } - width[Cnt] = width[0]; - memcpy(tmp, pset.name, size); - Models[Cnt++] = tmp; - *count = Cnt; - uflags |= C_RESULT; - } - } - mfree(&pset); + /* if endianness not specified, try + * little-endian then big-endian. + * NB: crossed-endian algorithms will not be + * searched. + */ + /* scan against preset models */ + if (~uflags & C_NOPCK) { + pass = 0; + int Cnt = 0; + do { + int psets = mcount(); - /* toggle refIn/refOut and reflect arguments */ - if (~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for (qptr = apolys; qptr < pptr; ++qptr) { - prevch(qptr, ibperhx); - } - } - } while (~rflags & R_HAVERI && ++pass < 2); - } - //got everything now free the memory... + while (psets) { + mbynum(&pset, --psets); - if (uflags & C_RESULT) { - for (qptr = apolys; qptr < pptr; ++qptr) { - pfree(qptr); - } - } - if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)){ - PrintAndLogEx(WARNING, "cannot search for crossed-endian models"); - return 0; - } - pass = 0; - do { - mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); - if (mptr && plen(mptr->spoly)) { - uflags |= C_RESULT; - } - while (mptr && plen(mptr->spoly)) { - mfree(mptr++); - } - free(candmods); - if (~rflags & R_HAVERI) { - model.flags ^= P_REFIN | P_REFOUT; - for (qptr = apolys; qptr < pptr; ++qptr) { - prevch(qptr, ibperhx); - } - } - } while (~rflags & R_HAVERI && ++pass < 2); - - for (qptr = apolys; qptr < pptr; ++qptr) { - pfree(qptr); - } - free(apolys); - mfree(&model); - - if (~uflags & C_RESULT){ - PrintAndLogEx(WARNING, "no models found"); - return 0; - } - } - return 1; + /* skip if different width, or refin or refout don't match */ + if (plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT)) + continue; + /* skip if the preset doesn't match specified parameters */ + if (rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly)) + continue; + if (rflags & R_HAVEI && psncmp(&model.init, &pset.init)) + continue; + if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) + continue; + + //for additional args (not used yet, maybe future?) + apoly = pclone(pset.xorout); + + if (pset.flags & P_REFOUT) + prev(&apoly); + + + for (qptr = apolys; qptr < pptr; ++qptr) { + crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); + if (ptst(crc)) { + pfree(&crc); + break; + } + pfree(&crc); + } + pfree(&apoly); + + if (qptr == pptr) { + + /* the selected model solved all arguments */ + mcanon(&pset); + + size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 7; + //PrintAndLogEx(NORMAL, "Size: %d, %s, count: %d",size,pset.name, Cnt); + char *tmp = calloc(size + 1, sizeof(char)); + if (tmp == NULL) { + PrintAndLogEx(WARNING, "out of memory?"); + return 0; + } + width[Cnt] = width[0]; + memcpy(tmp, pset.name, size); + Models[Cnt++] = tmp; + *count = Cnt; + uflags |= C_RESULT; + } + } + mfree(&pset); + + /* toggle refIn/refOut and reflect arguments */ + if (~rflags & R_HAVERI) { + model.flags ^= P_REFIN | P_REFOUT; + for (qptr = apolys; qptr < pptr; ++qptr) { + prevch(qptr, ibperhx); + } + } + } while (~rflags & R_HAVERI && ++pass < 2); + } + //got everything now free the memory... + + if (uflags & C_RESULT) { + for (qptr = apolys; qptr < pptr; ++qptr) { + pfree(qptr); + } + } + if (uflags & C_NOBFS && ~rflags & R_HAVEP) { + PrintAndLogEx(WARNING, "no models found"); + return 0; + } + + if (!(model.flags & P_REFIN) != !(model.flags & P_REFOUT)) { + PrintAndLogEx(WARNING, "cannot search for crossed-endian models"); + return 0; + } + pass = 0; + int args = 0; + do { + model_t *candmods = reveng(&model, qpoly, rflags, args, apolys); + model_t *mptr = candmods; + if (mptr && plen(mptr->spoly)) { + uflags |= C_RESULT; + } + while (mptr && plen(mptr->spoly)) { + mfree(mptr++); + } + free(candmods); + if (~rflags & R_HAVERI) { + model.flags ^= P_REFIN | P_REFOUT; + for (qptr = apolys; qptr < pptr; ++qptr) { + prevch(qptr, ibperhx); + } + } + } while (~rflags & R_HAVERI && ++pass < 2); + + for (qptr = apolys; qptr < pptr; ++qptr) { + pfree(qptr); + } + free(apolys); + mfree(&model); + + if (~uflags & C_RESULT) { + PrintAndLogEx(WARNING, "no models found"); + return 0; + } + } + return 1; } //-c || -v @@ -241,241 +228,271 @@ int GetModels(char *Models[], int *count, uint8_t *width){ //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified // l = little endian input and output, L = little endian output only, t = left justified} //result = calculated crc hex string -int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){ - /* default values */ - static model_t model = MZERO; - - int ibperhx = 8, obperhx = 8; - int rflags = 0; // search flags - int c; - poly_t apoly, crc; +int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result) { + /* default values */ + static model_t model = MZERO; - char *string; + int ibperhx = 8, obperhx = 8; +// int rflags = 0; // search flags + int c; + poly_t apoly, crc; - // stdin must be binary - #ifdef _WIN32 - _setmode(STDIN_FILENO, _O_BINARY); - #endif /* _WIN32 */ + char *string; - SETBMP(); - //set model - if (!(c = mbynam(&model, inModel))) { - PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets.", inModel); - return 0; - } - if (c < 0){ - PrintAndLogEx(WARNING, "no preset models available"); - return 0; - } - rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; - - //set flags - switch (endian) { - case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ - model.flags &= ~P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'B': /* B big-endian output (RefOut = false) */ - model.flags &= ~P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 'r': /* r right-justified */ - model.flags |= P_RTJUST; - break; - case 'l': /* l little-endian input and output */ - model.flags |= P_REFIN; - rflags |= R_HAVERI; - /* fall through: */ - case 'L': /* L little-endian output */ - model.flags |= P_REFOUT; - rflags |= R_HAVERO; - mnovel(&model); - /* fall through: */ - case 't': /* t left-justified */ - model.flags &= ~P_RTJUST; - break; - } - /* canonicalise the model, so the one we dump is the one we - * calculate with (not with -s, spoly may be blank which will - * normalise to zero and clear init and xorout.) - */ - mcanon(&model); + // stdin must be binary +#ifdef _WIN32 + _setmode(STDIN_FILENO, _O_BINARY); +#endif /* _WIN32 */ + + SETBMP(); + //set model + c = mbynam(&model, inModel); + if (!c) { + PrintAndLogEx(WARNING, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c); + return 0; + } + if (c < 0) { + PrintAndLogEx(WARNING, "no preset models available"); + return 0; + } +// rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX; + + //set flags + switch (endian) { + case 'b': /* b big-endian (RefIn = false, RefOut = false ) */ + model.flags &= ~P_REFIN; + //rflags |= R_HAVERI; + /* fall through: */ + case 'B': /* B big-endian output (RefOut = false) */ + model.flags &= ~P_REFOUT; + //rflags |= R_HAVERO; + mnovel(&model); + /* fall through: */ + case 'r': /* r right-justified */ + model.flags |= P_RTJUST; + break; + case 'l': /* l little-endian input and output */ + model.flags |= P_REFIN; + //rflags |= R_HAVERI; + /* fall through: */ + case 'L': /* L little-endian output */ + model.flags |= P_REFOUT; + //rflags |= R_HAVERO; + mnovel(&model); + /* fall through: */ + case 't': /* t left-justified */ + model.flags &= ~P_RTJUST; + break; + } + /* canonicalise the model, so the one we dump is the one we + * calculate with (not with -s, spoly may be blank which will + * normalise to zero and clear init and xorout.) + */ + mcanon(&model); - if (reverse) { - // v calculate reversed CRC - /* Distinct from the -V switch as this causes - * the arguments and output to be reversed as well. - */ - // reciprocate Poly - prcp(&model.spoly); + if (reverse) { + // v calculate reversed CRC + /* Distinct from the -V switch as this causes + * the arguments and output to be reversed as well. + */ + // reciprocate Poly + prcp(&model.spoly); - /* mrev() does: - * if(refout) prev(init); else prev(xorout); - * but here the entire argument polynomial is - * reflected, not just the characters, so RefIn - * and RefOut are not inverted as with -V. - * Consequently Init is the mirror image of the - * one resulting from -V, and so we have: - */ - if (~model.flags & P_REFOUT) { - prev(&model.init); - prev(&model.xorout); - } + /* mrev() does: + * if(refout) prev(init); else prev(xorout); + * but here the entire argument polynomial is + * reflected, not just the characters, so RefIn + * and RefOut are not inverted as with -V. + * Consequently Init is the mirror image of the + * one resulting from -V, and so we have: + */ + if (~model.flags & P_REFOUT) { + prev(&model.init); + prev(&model.xorout); + } - // swap init and xorout - apoly = model.init; - model.init = model.xorout; - model.xorout = apoly; - } - // c calculate CRC + // swap init and xorout + apoly = model.init; + model.init = model.xorout; + model.xorout = apoly; + } + // c calculate CRC - /* in the Williams model, xorout is applied after the refout stage. - * as refout is part of ptostr(), we reverse xorout here. - */ - if (model.flags & P_REFOUT) - prev(&model.xorout); + /* in the Williams model, xorout is applied after the refout stage. + * as refout is part of ptostr(), we reverse xorout here. + */ + if (model.flags & P_REFOUT) + prev(&model.xorout); - apoly = strtop(inHexStr, model.flags, ibperhx); + apoly = strtop(inHexStr, model.flags, ibperhx); - if (reverse) - prev(&apoly); + if (reverse) + prev(&apoly); - crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); + crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags); - if (reverse) - prev(&crc); + if (reverse) + prev(&crc); - string = ptostr(crc, model.flags, obperhx); - for (int i = 0; i < 50; i++){ - result[i] = string[i]; - if (result[i]==0) break; - } - free(string); - pfree(&crc); - pfree(&apoly); - return 1; + string = ptostr(crc, model.flags, obperhx); + for (int i = 0; i < 50; i++) { + result[i] = string[i]; + if (result[i] == 0) break; + } + free(string); + pfree(&crc); + pfree(&apoly); + return 1; } - +/* //test call to RunModel -int CmdrevengTestC(const char *Cmd){ - int cmdp = 0; - char inModel[30] = {0x00}; - char inHexStr[30] = {0x00}; - char result[30]; - int dataLen; - char endian = 0; - dataLen = param_getstr(Cmd, cmdp++, inModel, sizeof(inModel)); - if (dataLen < 4) return 0; - dataLen = param_getstr(Cmd, cmdp++, inHexStr, sizeof(inHexStr)); - if (dataLen < 4) return 0; - bool reverse = (param_get8(Cmd, cmdp++)) ? true : false; - endian = param_getchar(Cmd, cmdp++); +static int CmdrevengTestC(const char *Cmd) { + int cmdp = 0; + char inModel[30] = {0x00}; + char inHexStr[30] = {0x00}; + char result[30]; + int dataLen; + char endian = 0; + dataLen = param_getstr(Cmd, cmdp++, inModel, sizeof(inModel)); + if (dataLen < 4) return 0; + dataLen = param_getstr(Cmd, cmdp++, inHexStr, sizeof(inHexStr)); + if (dataLen < 4) return 0; + bool reverse = (param_get8(Cmd, cmdp++)) ? true : false; + endian = param_getchar(Cmd, cmdp++); - //PrintAndLogEx(NORMAL, "mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse); - int ans = RunModel(inModel, inHexStr, reverse, endian, result); - if (!ans) return 0; - - PrintAndLogEx(SUCCESS, "result: %s",result); - return 1; + //PrintAndLogEx(NORMAL, "mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse); + int ans = RunModel(inModel, inHexStr, reverse, endian, result); + if (!ans) return 0; + + PrintAndLogEx(SUCCESS, "result: %s", result); + return 1; } - +*/ //returns a calloced string (needs to be freed) -char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){ - char *tmp = calloc(len+1, sizeof(char)); - for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ - for (size_t i = 0; i < blockSize; i+=2){ - tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)]; - tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)]; - } - } - return tmp; +static char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize) { + char *tmp = calloc(len + 1, sizeof(char)); + for (uint8_t block = 0; block < (uint8_t)(len / blockSize); block++) { + for (size_t i = 0; i < blockSize; i += 2) { + tmp[i + (blockSize * block)] = inStr[(blockSize - 1 - i - 1) + (blockSize * block)]; + tmp[i + (blockSize * block) + 1] = inStr[(blockSize - 1 - i) + (blockSize * block)]; + } + } + return tmp; } // takes hex string in and searches for a matching result (hex string must include checksum) -int CmdrevengSearch(const char *Cmd){ +static int CmdrevengSearch(const char *Cmd) { -#define NMODELS 103 - - char inHexStr[100] = {0x00}; - int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); - if (dataLen < 4) return 0; +#define NMODELS 106 - // these two arrays, must match preset size. - char *Models[NMODELS]; - uint8_t width[NMODELS] = {0}; - int count = 0; + char inHexStr[100] = {0x00}; + int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); + if (dataLen < 4) return 0; - uint8_t crcChars = 0; - char result[30]; - char revResult[30]; - int ans = GetModels(Models, &count, width); - bool found = false; - if (!ans) return 0; - - // try each model and get result - for (int i = 0; i < count; i++){ - /*if (found) { - free(Models[i]); - continue; - }*/ - // round up to # of characters in this model's crc - crcChars = ((width[i]+7)/8)*2; - // can't test a model that has more crc digits than our data - if (crcChars >= dataLen) - continue; - memset(result, 0, 30); - char *inCRC = calloc(crcChars+1, sizeof(char)); - memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars); + // these two arrays, must match preset size. + char *Models[NMODELS]; + uint8_t width[NMODELS] = {0}; + int count = 0; - char *outHex = calloc(dataLen-crcChars+1, sizeof(char)); - memcpy(outHex, inHexStr, dataLen-crcChars); + char result[30]; + char revResult[30]; + int ans = GetModels(Models, &count, width); + bool found = false; + if (!ans) return 0; + + // try each model and get result + for (int i = 0; i < count; i++) { + /*if (found) { + free(Models[i]); + continue; + }*/ + // round up to # of characters in this model's crc + uint8_t crcChars = ((width[i] + 7) / 8) * 2; + // can't test a model that has more crc digits than our data + if (crcChars >= dataLen) + continue; + + PrintAndLogEx(DEBUG + , "DEBUG: dataLen %d, crcChars %u, width[i] %u" + , dataLen + , crcChars + , width[i] + ); + + if (crcChars == 0) + continue; + + memset(result, 0, 30); + char *inCRC = calloc(crcChars + 1, sizeof(char)); + memcpy(inCRC, inHexStr + (dataLen - crcChars), crcChars); + + char *outHex = calloc(dataLen - crcChars + 1, sizeof(char)); + memcpy(outHex, inHexStr, dataLen - crcChars); + + ans = RunModel(Models[i], outHex, false, 0, result); + if (ans) { + // test for match + if (memcmp(result, inCRC, crcChars) == 0) { + PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value: %s\n", Models[i], result); + //optional - stop searching if found... + found = true; + } else { + if (crcChars > 2) { + char *swapEndian = SwapEndianStr(result, crcChars, crcChars); + if (memcmp(swapEndian, inCRC, crcChars) == 0) { + PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value endian swapped: %s\n", Models[i], swapEndian); + // optional - stop searching if found... + found = true; + } + free(swapEndian); + } + } + } + ans = RunModel(Models[i], outHex, true, 0, revResult); + if (ans) { + // test for match + if (memcmp(revResult, inCRC, crcChars) == 0) { + PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value: %s\n", Models[i], revResult); + // optional - stop searching if found... + found = true; + } else { + if (crcChars > 2) { + char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); + if (memcmp(swapEndian, inCRC, crcChars) == 0) { + PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value endian swapped: %s\n", Models[i], swapEndian); + // optional - stop searching if found... + found = true; + } + free(swapEndian); + } + } + } + free(inCRC); + free(outHex); + free(Models[i]); + } + + if (!found) PrintAndLogEx(FAILED, "\nno matches found\n"); + return 1; +} + +int CmdCrc(const char *Cmd) { + char name[] = {"reveng "}; + char Cmd2[100 + 7]; + memcpy(Cmd2, name, 7); + memcpy(Cmd2 + 7, Cmd, 100); + char *argv[MAX_ARGS]; + int argc = split(Cmd2, argv); + + if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) { + CmdrevengSearch(argv[2]); + } else { + reveng_main(argc, argv); + } + for (int i = 0; i < argc; ++i) { + free(argv[i]); + } + return 0; +} - // PrintAndLogEx(DEBUG, "DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex); - ans = RunModel(Models[i], outHex, false, 0, result); - if (ans) { - // test for match - if (memcmp(result, inCRC, crcChars) == 0){ - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value: %s\n", Models[i], result); - //optional - stop searching if found... - found = true; - } else { - if (crcChars > 2){ - char *swapEndian = SwapEndianStr(result, crcChars, crcChars); - if (memcmp(swapEndian, inCRC, crcChars) == 0){ - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel: %s | value endian swapped: %s\n", Models[i], swapEndian); - // optional - stop searching if found... - found = true; - } - free(swapEndian); - } - } - } - ans = RunModel(Models[i], outHex, true, 0, revResult); - if (ans) { - // test for match - if (memcmp(revResult, inCRC, crcChars) == 0){ - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value: %s\n", Models[i], revResult); - // optional - stop searching if found... - found = true; - } else { - if (crcChars > 2){ - char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars); - if (memcmp(swapEndian, inCRC, crcChars) == 0){ - PrintAndLogEx(SUCCESS, "\nfound possible match\nmodel reversed: %s | value endian swapped: %s\n", Models[i], swapEndian); - // optional - stop searching if found... - found = true; - } - free(swapEndian); - } - } - } - free(inCRC); - free(outHex); - free(Models[i]); - } - - if (!found) PrintAndLogEx(FAILED, "\nno matches found\n"); - return 1; -} \ No newline at end of file diff --git a/client/cmdcrc.h b/client/cmdcrc.h index ba9540c45..e45c004f5 100644 --- a/client/cmdcrc.h +++ b/client/cmdcrc.h @@ -28,9 +28,8 @@ #include "ui.h" #include "util.h" -extern int CmdCrc(const char *Cmd); +int CmdCrc(const char *Cmd); -extern int CmdrevengSearch(const char *Cmd); -extern int GetModels(char *Models[], int *count, uint8_t *width); -extern int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result); +int GetModels(char *Models[], int *count, uint8_t *width); +int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result); #endif diff --git a/client/cmddata.c b/client/cmddata.c index 57aec5b70..d6a4e8e73 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -10,304 +10,308 @@ #include "cmddata.h" uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; -//uint8_t g_debugMode = 0; size_t DemodBufferLen = 0; size_t g_DemodStartIdx = 0; int g_DemodClock = 0; static int CmdHelp(const char *Cmd); -int usage_data_printdemodbuf(void){ - PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " x output in hex (omit for binary output)"); - PrintAndLogEx(NORMAL, " o enter offset in # of bits"); - PrintAndLogEx(NORMAL, " l enter length to print in # of bits or hex characters respectively"); - return 0; +static int usage_data_printdemodbuf(void) { + PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " x output in hex (omit for binary output)"); + PrintAndLogEx(NORMAL, " o enter offset in # of bits"); + PrintAndLogEx(NORMAL, " l enter length to print in # of bits or hex characters respectively"); + return PM3_SUCCESS; } -int usage_data_manrawdecode(void){ - PrintAndLogEx(NORMAL, "Usage: data manrawdecode [invert] [maxErr]"); - PrintAndLogEx(NORMAL, " Takes 10 and 01 and converts to 0 and 1 respectively"); - PrintAndLogEx(NORMAL, " --must have binary sequence in demodbuffer (run data askrawdemod first)"); - PrintAndLogEx(NORMAL, " [invert] invert output"); - PrintAndLogEx(NORMAL, " [maxErr] set number of errors allowed (default = 20)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data manrawdecode = decode manchester bitstream from the demodbuffer"); - return 0; +static int usage_data_manrawdecode(void) { + PrintAndLogEx(NORMAL, "Usage: data manrawdecode [invert] [maxErr]"); + PrintAndLogEx(NORMAL, " Takes 10 and 01 and converts to 0 and 1 respectively"); + PrintAndLogEx(NORMAL, " --must have binary sequence in demodbuffer (run data askrawdemod first)"); + PrintAndLogEx(NORMAL, " [invert] invert output"); + PrintAndLogEx(NORMAL, " [maxErr] set number of errors allowed (default = 20)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data manrawdecode = decode manchester bitstream from the demodbuffer"); + return PM3_SUCCESS; } -int usage_data_biphaserawdecode(void){ - PrintAndLogEx(NORMAL, "Usage: data biphaserawdecode [offset] [invert] [maxErr]"); - PrintAndLogEx(NORMAL, " Converts 10 or 01 to 1 and 11 or 00 to 0"); - PrintAndLogEx(NORMAL, " --must have binary sequence in demodbuffer (run data askrawdemod first)"); - PrintAndLogEx(NORMAL, " --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " [offset <0|1>], set to 0 not to adjust start position or to 1 to adjust decode start position"); - PrintAndLogEx(NORMAL, " [invert <0|1>], set to 1 to invert output"); - PrintAndLogEx(NORMAL, " [maxErr int], set max errors tolerated - default=20"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data biphaserawdecode = decode biphase bitstream from the demodbuffer"); - PrintAndLogEx(NORMAL, " Example: data biphaserawdecode 1 1 = decode biphase bitstream from the demodbuffer, set offset, and invert output"); - return 0; +static int usage_data_biphaserawdecode(void) { + PrintAndLogEx(NORMAL, "Usage: data biphaserawdecode [offset] [invert] [maxErr]"); + PrintAndLogEx(NORMAL, " Converts 10 or 01 to 1 and 11 or 00 to 0"); + PrintAndLogEx(NORMAL, " --must have binary sequence in demodbuffer (run data askrawdemod first)"); + PrintAndLogEx(NORMAL, " --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " [offset <0|1>], set to 0 not to adjust start position or to 1 to adjust decode start position"); + PrintAndLogEx(NORMAL, " [invert <0|1>], set to 1 to invert output"); + PrintAndLogEx(NORMAL, " [maxErr int], set max errors tolerated - default=20"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data biphaserawdecode = decode biphase bitstream from the demodbuffer"); + PrintAndLogEx(NORMAL, " Example: data biphaserawdecode 1 1 = decode biphase bitstream from the demodbuffer, set offset, and invert output"); + return PM3_SUCCESS; } -int usage_data_rawdemod(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod [modulation] |"); - PrintAndLogEx(NORMAL, " [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); - PrintAndLogEx(NORMAL, " 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); - PrintAndLogEx(NORMAL, " as 'h', prints the help for the specific modulation"); - PrintAndLogEx(NORMAL, " see specific modulation help for optional parameters"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod fs h = print help specific to fsk demod"); - PrintAndLogEx(NORMAL, " : data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); - return 0; +static int usage_data_rawdemod(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod [modulation] |"); + PrintAndLogEx(NORMAL, " [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); + PrintAndLogEx(NORMAL, " 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); + PrintAndLogEx(NORMAL, " as 'h', prints the help for the specific modulation"); + PrintAndLogEx(NORMAL, " see specific modulation help for optional parameters"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod fs h = print help specific to fsk demod"); + PrintAndLogEx(NORMAL, " : data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); + return PM3_SUCCESS; } -int usage_data_rawdemod_am(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); - PrintAndLogEx(NORMAL, " ['s'] optional, check for Sequence Terminator"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); - PrintAndLogEx(NORMAL, " , 1 to invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); - PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); - PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod am = demod an ask/manchester tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_am(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); + PrintAndLogEx(NORMAL, " ['s'] optional, check for Sequence Terminator"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); + PrintAndLogEx(NORMAL, " , 1 to invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); + PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); + PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod am = demod an ask/manchester tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_rawdemod_ab(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod ab [offset] [clock] [maxError] [maxLen] "); - PrintAndLogEx(NORMAL, " [offset], offset to begin biphase, default=0"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); - PrintAndLogEx(NORMAL, " , 1 to invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); - PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); - PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLogEx(NORMAL, " NOTE: can be entered as second or third argument"); - PrintAndLogEx(NORMAL, " NOTE: can be entered as first, second or last argument"); - PrintAndLogEx(NORMAL, " NOTE: any other arg must have previous args set to work"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod ab = demod an ask/biph tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 1 32 = demod an ask/biph tag from GraphBuffer using an offset of 1 and a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 32 1 = demod an ask/biph tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 1 = demod an ask/biph tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : 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"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_ab(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod ab [offset] [clock] [maxError] [maxLen] "); + PrintAndLogEx(NORMAL, " [offset], offset to begin biphase, default=0"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); + PrintAndLogEx(NORMAL, " , 1 to invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); + PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); + PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); + PrintAndLogEx(NORMAL, " NOTE: can be entered as second or third argument"); + PrintAndLogEx(NORMAL, " NOTE: can be entered as first, second or last argument"); + PrintAndLogEx(NORMAL, " NOTE: any other arg must have previous args set to work"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod ab = demod an ask/biph tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); + PrintAndLogEx(NORMAL, " : data rawdemod ab 1 32 = demod an ask/biph tag from GraphBuffer using an offset of 1 and a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod ab 0 32 1 = demod an ask/biph tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " : data rawdemod ab 0 1 = demod an ask/biph tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " : 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"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_rawdemod_ar(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod ar [clock] [maxError] [maxLen] [amplify]"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); - PrintAndLogEx(NORMAL, " , 1 to invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); - PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (1024 bits at rf/64)"); - PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod ar = demod an ask tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : 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"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_ar(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod ar [clock] [maxError] [maxLen] [amplify]"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect"); + PrintAndLogEx(NORMAL, " , 1 to invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100"); + PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (1024 bits at rf/64)"); + PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod ar = demod an ask tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); + PrintAndLogEx(NORMAL, " : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " : 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"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_rawdemod_fs(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod fs [clock] [fchigh] [fclow]"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, omit for autodetect."); - PrintAndLogEx(NORMAL, " , 1 for invert output, can be used even if the clock is omitted"); - PrintAndLogEx(NORMAL, " [fchigh], larger field clock length, omit for autodetect"); - PrintAndLogEx(NORMAL, " [fclow], small field clock length, omit for autodetect"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer"); - return 0; +static int usage_data_rawdemod_fs(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod fs [clock] [fchigh] [fclow]"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, omit for autodetect."); + PrintAndLogEx(NORMAL, " , 1 for invert output, can be used even if the clock is omitted"); + PrintAndLogEx(NORMAL, " [fchigh], larger field clock length, omit for autodetect"); + PrintAndLogEx(NORMAL, " [fclow], small field clock length, omit for autodetect"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer"); + return PM3_SUCCESS; } -int usage_data_rawdemod_nr(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod nr [clock] <0|1> [maxError]"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); - PrintAndLogEx(NORMAL, " , 1 for invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_nr(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod nr [clock] <0|1> [maxError]"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); + PrintAndLogEx(NORMAL, " , 1 for invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod nr 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " : data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_rawdemod_p1(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod p1 [clock] <0|1> [maxError]"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); - PrintAndLogEx(NORMAL, " , 1 for invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod p1 = demod a psk1 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 32 1 = demod a psk1 tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_p1(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod p1 [clock] <0|1> [maxError]"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); + PrintAndLogEx(NORMAL, " , 1 for invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod p1 = demod a psk1 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " : data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod p1 32 1 = demod a psk1 tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " : data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_rawdemod_p2(void){ - PrintAndLogEx(NORMAL, "Usage: data rawdemod p2 [clock] <0|1> [maxError]"); - PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); - PrintAndLogEx(NORMAL, " , 1 for invert output"); - PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 32 1 = demod a psk2 tag from GraphBuffer using a clock of RF/32 and inverting output"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); - PrintAndLogEx(NORMAL, " : 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; +static int usage_data_rawdemod_p2(void) { + PrintAndLogEx(NORMAL, "Usage: data rawdemod p2 [clock] <0|1> [maxError]"); + PrintAndLogEx(NORMAL, " [set clock as integer] optional, if not set, autodetect."); + PrintAndLogEx(NORMAL, " , 1 for invert output"); + PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); + PrintAndLogEx(NORMAL, " : data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " : data rawdemod p2 32 1 = demod a psk2 tag from GraphBuffer using a clock of RF/32 and inverting output"); + PrintAndLogEx(NORMAL, " : data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); + PrintAndLogEx(NORMAL, " : 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 PM3_SUCCESS; } -int usage_data_autocorr(void) { - PrintAndLogEx(NORMAL, "Autocorrelate is used to detect repeating sequences. We use it as detection of length in bits a message inside the signal is"); - PrintAndLogEx(NORMAL, "Usage: data autocorr w [g]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " w window length for correlation - default = 4000"); - PrintAndLogEx(NORMAL, " g save back to GraphBuffer (overwrite)"); - return 0; +static int usage_data_autocorr(void) { + PrintAndLogEx(NORMAL, "Autocorrelate is used to detect repeating sequences. We use it as detection of length in bits a message inside the signal is"); + PrintAndLogEx(NORMAL, "Usage: data autocorr w [g]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " w window length for correlation - default = 4000"); + PrintAndLogEx(NORMAL, " g save back to GraphBuffer (overwrite)"); + return PM3_SUCCESS; } -int usage_data_undecimate(void){ - PrintAndLogEx(NORMAL, "Usage: data undec [factor]"); - PrintAndLogEx(NORMAL, "This function performs un-decimation, by repeating each sample N times"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " factor The number of times to repeat each sample.[default:2]"); - PrintAndLogEx(NORMAL, "Example: 'data undec 3'"); - return 0; +static int usage_data_undecimate(void) { + PrintAndLogEx(NORMAL, "Usage: data undec [factor]"); + PrintAndLogEx(NORMAL, "This function performs un-decimation, by repeating each sample N times"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " factor The number of times to repeat each sample.[default:2]"); + PrintAndLogEx(NORMAL, "Example: 'data undec 3'"); + return PM3_SUCCESS; } -int usage_data_detectclock(void){ - PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] "); - PrintAndLogEx(NORMAL, " [modulation as char], specify the modulation type you want to detect the clock of"); - PrintAndLogEx(NORMAL, " , specify the clock (optional - to get best start position only)"); - PrintAndLogEx(NORMAL, " 'a' = ask, 'f' = fsk, 'n' = nrz/direct, 'p' = psk"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data detectclock a = detect the clock of an ask modulated wave in the GraphBuffer"); - PrintAndLogEx(NORMAL, " data detectclock f = detect the clock of an fsk modulated wave in the GraphBuffer"); - PrintAndLogEx(NORMAL, " data detectclock p = detect the clock of an psk modulated wave in the GraphBuffer"); - PrintAndLogEx(NORMAL, " data detectclock n = detect the clock of an nrz/direct modulated wave in the GraphBuffer"); - return 0; +static int usage_data_detectclock(void) { + PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] "); + PrintAndLogEx(NORMAL, " [modulation as char], specify the modulation type you want to detect the clock of"); + PrintAndLogEx(NORMAL, " , specify the clock (optional - to get best start position only)"); + PrintAndLogEx(NORMAL, " 'a' = ask, 'f' = fsk, 'n' = nrz/direct, 'p' = psk"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Example: data detectclock a = detect the clock of an ask modulated wave in the GraphBuffer"); + PrintAndLogEx(NORMAL, " data detectclock f = detect the clock of an fsk modulated wave in the GraphBuffer"); + PrintAndLogEx(NORMAL, " data detectclock p = detect the clock of an psk modulated wave in the GraphBuffer"); + PrintAndLogEx(NORMAL, " data detectclock n = detect the clock of an nrz/direct modulated wave in the GraphBuffer"); + return PM3_SUCCESS; } -int usage_data_hex2bin(void){ - PrintAndLogEx(NORMAL, "Usage: data hex2bin "); - PrintAndLogEx(NORMAL, " This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); - return 0; +static int usage_data_hex2bin(void) { + PrintAndLogEx(NORMAL, "Usage: data hex2bin "); + PrintAndLogEx(NORMAL, " This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); + return PM3_SUCCESS; } -int usage_data_bin2hex(void){ - PrintAndLogEx(NORMAL, "Usage: data bin2hex "); - PrintAndLogEx(NORMAL, " This function will ignore all characters not 1 or 0 (but stop reading on whitespace)"); - return 0; +static int usage_data_bin2hex(void) { + PrintAndLogEx(NORMAL, "Usage: data bin2hex "); + PrintAndLogEx(NORMAL, " This function will ignore all characters not 1 or 0 (but stop reading on whitespace)"); + return PM3_SUCCESS; } -int usage_data_buffclear(void){ - PrintAndLogEx(NORMAL, "This function clears the bigbuff on deviceside"); - PrintAndLogEx(NORMAL, "Usage: data buffclear [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - return 0; +static int usage_data_buffclear(void) { + PrintAndLogEx(NORMAL, "This function clears the bigbuff on deviceside"); + PrintAndLogEx(NORMAL, "Usage: data buffclear [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + return PM3_SUCCESS; } -int usage_data_fsktonrz() { - PrintAndLogEx(NORMAL, "Usage: data fsktonrz c l f "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " c enter the a clock (omit to autodetect)"); - PrintAndLogEx(NORMAL, " l enter a field clock (omit to autodetect)"); - PrintAndLogEx(NORMAL, " f enter a field clock (omit to autodetect)"); - return 0; +static int usage_data_fsktonrz() { + PrintAndLogEx(NORMAL, "Usage: data fsktonrz c l f "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " c enter the a clock (omit to autodetect)"); + PrintAndLogEx(NORMAL, " l enter a field clock (omit to autodetect)"); + PrintAndLogEx(NORMAL, " f enter a field clock (omit to autodetect)"); + return PM3_SUCCESS; } + //set the demod buffer with given array of binary (one bit per byte) //by marshmellow -void setDemodBuf(uint8_t *buf, size_t size, size_t start_idx) { - if (buf == NULL) return; +void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx) { + if (buff == NULL) return; - if ( size > MAX_DEMOD_BUF_LEN - start_idx) - size = MAX_DEMOD_BUF_LEN - start_idx; - - for (size_t i = 0; i < size; i++) - DemodBuffer[i] = buf[start_idx++]; - - DemodBufferLen = size; + if (size > MAX_DEMOD_BUF_LEN - start_idx) + size = MAX_DEMOD_BUF_LEN - start_idx; + + for (size_t i = 0; i < size; i++) + DemodBuffer[i] = buff[start_idx++]; + + DemodBufferLen = size; } -bool getDemodBuf(uint8_t *buf, size_t *size) { - if (buf == NULL) return false; - if (size == NULL) return false; - if (*size == 0) return false; +bool getDemodBuff(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; + *size = (*size > DemodBufferLen) ? DemodBufferLen : *size; - memcpy(buf, DemodBuffer, *size); - return true; + memcpy(buff, DemodBuffer, *size); + return true; } // include // Root mean square -double rms(double *v, size_t n) { - double sum = 0.0; - for(size_t i = 0; i < n; i++) - sum += v[i] * v[i]; - return sqrt(sum / n); +/* +static double rms(double *v, size_t n) { + double sum = 0.0; + for (size_t i = 0; i < n; i++) + sum += v[i] * v[i]; + return sqrt(sum / n); } -int cmp_int( const void *a, const void *b) { - if (*(const int *)a < *(const int *)b) - return -1; - else - return *(const int *)a > *(const int *)b; + +static int cmp_int(const void *a, const void *b) { + if (*(const int *)a < * (const int *)b) + return -1; + else + return *(const int *)a > *(const int *)b; } -int cmp_uint8( const void *a, const void *b) { - if (*(const uint8_t *)a < *(const uint8_t *)b) - return -1; - else - return *(const uint8_t *)a > *(const uint8_t *)b; +static int cmp_uint8(const void *a, const void *b) { + if (*(const uint8_t *)a < * (const uint8_t *)b) + return -1; + else + return *(const uint8_t *)a > *(const uint8_t *)b; } // Median of a array of values -double median_int( int *src, size_t size ) { - qsort( src, size, sizeof(int), cmp_int); - return 0.5 * ( src[size/2] + src[(size-1)/2]); + +static double median_int(int *src, size_t size) { + qsort(src, size, sizeof(int), cmp_int); + return 0.5 * (src[size / 2] + src[(size - 1) / 2]); } -double median_uint8( uint8_t *src, size_t size ) { - qsort( src, size, sizeof(uint8_t), cmp_uint8); - return 0.5 * ( src[size/2] + src[(size-1)/2]); +static double median_uint8(uint8_t *src, size_t size) { + qsort(src, size, sizeof(uint8_t), cmp_uint8); + return 0.5 * (src[size / 2] + src[(size - 1) / 2]); } +*/ // function to compute mean for a series static double compute_mean(const int *data, size_t n) { - double mean = 0.0; - for (size_t i=0; i < n; i++) - mean += data[i]; - mean /= n; - return mean; + double mean = 0.0; + for (size_t i = 0; i < n; i++) + mean += data[i]; + mean /= n; + return mean; } // function to compute variance for a series static double compute_variance(const int *data, size_t n) { - double variance = 0.0; - double mean = compute_mean(data, n); + double variance = 0.0; + double mean = compute_mean(data, n); - for (size_t i=0; i < n; i++) - variance += pow(( data[i] - mean), 2.0); + for (size_t i = 0; i < n; i++) + variance += pow((data[i] - mean), 2.0); - variance /= n; - return variance; + variance /= n; + return variance; } // Function to compute autocorrelation for a series @@ -315,133 +319,142 @@ static double compute_variance(const int *data, size_t n) { // - Corrected divide by n to divide (n - lag) from Tobias Mueller /* static double compute_autoc(const int *data, size_t n, int lag) { - double autocv = 0.0; // Autocovariance value - double ac_value; // Computed autocorrelation value to be returned - double variance; // Computed variance - double mean; - - mean = compute_mean(data, n); - variance = compute_variance(data, n); - - for (size_t i=0; i < (n - lag); i++) - autocv += (data[i] - mean) * (data[i+lag] - mean); + double autocv = 0.0; // Autocovariance value + double ac_value; // Computed autocorrelation value to be returned + double variance; // Computed variance + double mean; - autocv = (1.0 / (n - lag)) * autocv; + mean = compute_mean(data, n); + variance = compute_variance(data, n); - // Autocorrelation is autocovariance divided by variance - ac_value = autocv / variance; - return ac_value; + for (size_t i=0; i < (n - lag); i++) + autocv += (data[i] - mean) * (data[i+lag] - mean); + + autocv = (1.0 / (n - lag)) * autocv; + + // Autocorrelation is autocovariance divided by variance + ac_value = autocv / variance; + return ac_value; } */ // 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 size_t savedDemodStartIdx = 0; - static int savedDemodClock = 0; + static uint8_t SavedDB[MAX_DEMOD_BUF_LEN]; + static size_t SavedDBlen; + static bool DB_Saved = false; + static size_t savedDemodStartIdx = 0; + static int savedDemodClock = 0; - if (saveOpt == GRAPH_SAVE) { //save + 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; - } -} + memcpy(SavedDB, DemodBuffer, sizeof(DemodBuffer)); + SavedDBlen = DemodBufferLen; + DB_Saved = true; + savedDemodStartIdx = g_DemodStartIdx; + savedDemodClock = g_DemodClock; + } else if (DB_Saved) { //restore -int CmdSetDebugMode(const char *Cmd) { - int demod = 0; - sscanf(Cmd, "%i", &demod); - g_debugMode = (uint8_t)demod; - return 1; + memcpy(DemodBuffer, SavedDB, sizeof(DemodBuffer)); + DemodBufferLen = SavedDBlen; + g_DemodClock = savedDemodClock; + g_DemodStartIdx = savedDemodStartIdx; + } +} + +static int CmdSetDebugMode(const char *Cmd) { + int demod = 0; + sscanf(Cmd, "%i", &demod); + g_debugMode = (uint8_t)demod; + return PM3_SUCCESS; } //by marshmellow -// max output to 512 bits if we have more - should be plenty +// max output to 512 bits if we have more +// doesn't take inconsideration where the demod offset or bitlen found. void printDemodBuff(void) { - int len = DemodBufferLen; - if (len < 1) { - PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer"); - return; - } - if (len > 512) len = 512; + int len = DemodBufferLen; + if (len < 1) { + PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer"); + return; + } + if (len > 512) len = 512; - PrintAndLogEx(NORMAL, "%s", sprint_bin_break(DemodBuffer, len, 16) ); + PrintAndLogEx(NORMAL, "%s", sprint_bin_break(DemodBuffer, len, 32)); } int CmdPrintDemodBuff(const char *Cmd) { - char hex[512] = {0x00}; - bool hexMode = false; - bool errors = false; - uint32_t offset = 0; - uint32_t length = 512; - char cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_data_printdemodbuf(); - case 'x': - hexMode = true; - cmdp++; - break; - case 'o': - offset = param_get32ex(Cmd, cmdp+1, 0, 10); - if (!offset) errors = true; - cmdp += 2; - break; - case 'l': - length = param_get32ex(Cmd, cmdp+1, 512, 10); - if (!length) errors = true; - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_data_printdemodbuf(); - - if (DemodBufferLen == 0) { - PrintAndLogEx(NORMAL, "Demodbuffer is empty"); - return 0; - } - length = (length > (DemodBufferLen-offset)) ? DemodBufferLen-offset : length; - int numBits = (length) & 0x00FFC; //make sure we don't exceed our string + bool hexMode = false; + bool errors = false; + uint32_t offset = 0; + uint32_t length = 512; + char cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_data_printdemodbuf(); + case 'x': + hexMode = true; + cmdp++; + break; + case 'o': + offset = param_get32ex(Cmd, cmdp + 1, 0, 10); + if (!offset) errors = true; + cmdp += 2; + break; + case 'l': + length = param_get32ex(Cmd, cmdp + 1, 512, 10); + if (!length) errors = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors) return usage_data_printdemodbuf(); - if (hexMode){ - char *buf = (char *) (DemodBuffer + offset); - numBits = (numBits > sizeof(hex)) ? sizeof(hex) : numBits; - numBits = binarraytohex(hex, buf, numBits); - if (numBits == 0) { - return 0; - } - PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex); - } else { - PrintAndLogEx(NORMAL, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer+offset, numBits, 16)); - } - return 1; + if (DemodBufferLen == 0) { + PrintAndLogEx(NORMAL, "Demodbuffer is empty"); + return PM3_ESOFT; + } + length = (length > (DemodBufferLen - offset)) ? DemodBufferLen - offset : length; + + if (hexMode) { + char *buf = (char *)(DemodBuffer + offset); + char hex[512] = {0x00}; + int numBits = binarraytohex(hex, sizeof(hex), buf, length); + if (numBits == 0) { + return PM3_ESOFT; + } + PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex); + } else { + PrintAndLogEx(NORMAL, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32)); + } + return PM3_SUCCESS; } //by marshmellow //this function strictly converts >1 to 1 and <1 to 0 for each sample in the graphbuffer int CmdGetBitStream(const char *Cmd) { - CmdHpf(Cmd); - for (uint32_t i = 0; i < GraphTraceLen; i++) - GraphBuffer[i] = (GraphBuffer[i] >= 1) ? 1 : 0; - - RepaintGraphWindow(); - return 0; + CmdHpf(Cmd); + for (uint32_t i = 0; i < GraphTraceLen; i++) + GraphBuffer[i] = (GraphBuffer[i] >= 1) ? 1 : 0; + + RepaintGraphWindow(); + return PM3_SUCCESS; +} +int CmdConvertBitStream(const char *Cmd) { + + if (isGraphBitstream()) { + convertGraphFromBitstream(); + } else { + // get high, low + convertGraphFromBitstreamEx(-126, -127); + } + return PM3_SUCCESS; } //by marshmellow @@ -449,404 +462,445 @@ int CmdGetBitStream(const char *Cmd) { // (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 +//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}; + int invert = 0; + int clk = 0; + int maxErr = 100; + size_t maxLen = 0; + uint8_t askamp = 0; + char amp = tolower(param_getchar(Cmd, 0)); + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; - sscanf(Cmd, "%i %i %i %i %c", &clk, &invert, &maxErr, &maxLen, &); + sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - if (!maxLen) maxLen = BIGBUF_SIZE; + if (!maxLen) maxLen = BIGBUF_SIZE; - if (invert != 0 && invert != 1) { - PrintAndLogEx(WARNING, "Invalid argument: %s", Cmd); - return 0; - } + if (invert != 0 && invert != 1) { + PrintAndLogEx(WARNING, "Invalid argument: %s", Cmd); + return PM3_EINVARG; + } - if (clk == 1) { - invert = 1; - clk = 0; - } + if (clk == 1) { + invert = 1; + clk = 0; + } - size_t BitLen = getFromGraphBuf(BitStream); + size_t BitLen = getFromGraphBuf(bits); - PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) Bitlen from grphbuff: %d", BitLen); + PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) #samples from graphbuff: %d", BitLen); - if (BitLen < 255) return 0; + if (BitLen < 255) return PM3_ESOFT; - if (maxLen < BitLen && maxLen != 0) BitLen = maxLen; + if (maxLen < BitLen && maxLen != 0) BitLen = maxLen; - int foundclk = 0; - //amp before ST check - if (amp == 'a' || amp == 'A') - askAmp(BitStream, BitLen); + int foundclk = 0; - bool st = false; - size_t ststart = 0, stend = 0; - if (*stCheck) - st = DetectST(BitStream, &BitLen, &foundclk, &ststart, &stend); + //amplify signal before ST check + if (amp == 'a') { + askAmp(bits, BitLen); + } - if (st) { - *stCheck = st; - clk = (clk == 0) ? foundclk : clk; - CursorCPos = ststart; - CursorDPos = stend; - if (verbose || g_debugMode) - PrintAndLogEx(NORMAL, "Found Sequence Terminator - First one is shown by orange and blue graph markers"); - } + size_t ststart = 0, stend = 0; +// if (*stCheck) + bool st = DetectST(bits, &BitLen, &foundclk, &ststart, &stend); - int startIdx = 0; - int errCnt = askdemod_ext(BitStream, &BitLen, &clk, &invert, maxErr, askamp, askType, &startIdx); + if (clk == 0) { + if (foundclk == 32 || foundclk == 64) { + clk = foundclk; + } + } - if (errCnt < 0 || BitLen < 16){ //if fatal error (or -1) - PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) No data found errors:%d, invert:%d, bitlen:%d, clock:%d", errCnt, invert, BitLen, clk); - return 0; - } + if (st) { + *stCheck = st; + CursorCPos = ststart; + CursorDPos = stend; + if (verbose) + PrintAndLogEx(DEBUG, "Found Sequence Terminator - First one is shown by orange / blue graph markers"); + } - if (errCnt > maxErr){ - PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) Too many errors found, errors:%d, bits:%d, clock:%d", errCnt, BitLen, clk); - return 0; - } - - if (verbose || g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) Using clock:%d, invert:%d, bits found:%d", clk, invert, BitLen); + int startIdx = 0; + int errCnt = askdemod_ext(bits, &BitLen, &clk, &invert, maxErr, askamp, askType, &startIdx); - //output - setDemodBuf(BitStream,BitLen,0); - setClockGrid(clk, startIdx); + if (errCnt < 0 || BitLen < 16) { //if fatal error (or -1) + PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) No data found errors:%d, invert:%c, bitlen:%d, clock:%d", errCnt, (invert) ? 'Y' : 'N', BitLen, clk); + return PM3_ESOFT; + } - if (verbose || g_debugMode){ - if (errCnt > 0) - PrintAndLogEx(NORMAL, "# Errors during Demoding (shown as 7 in bit stream): %d",errCnt); - if (askType) - PrintAndLogEx(NORMAL, "ASK/Manchester - Clock: %d - Decoded bitstream:",clk); - else - PrintAndLogEx(NORMAL, "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); + if (errCnt > maxErr) { + PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) Too many errors found, errors:%d, bits:%d, clock:%d", errCnt, BitLen, clk); + return PM3_ESOFT; + } - return 1; + if (verbose) PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) Using clock:%d, invert:%d, bits found:%d, start index %d", clk, invert, BitLen, startIdx); + + //output + setDemodBuff(bits, BitLen, 0); + setClockGrid(clk, startIdx); + + if (verbose) { + if (errCnt > 0) + PrintAndLogEx(DEBUG, "# Errors during Demoding (shown as 7 in bit stream): %d", errCnt); + if (askType) + PrintAndLogEx(DEBUG, "ASK/Manchester - Clock: %d - Decoded bitstream:", clk); + else + PrintAndLogEx(DEBUG, "ASK/Raw - Clock: %d - Decoded bitstream:", clk); + + printDemodBuff(); + } + uint64_t lo = 0; + uint32_t hi = 0; + if (emSearch) + AskEm410xDecode(true, &hi, &lo); + + return PM3_SUCCESS; } int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) { - bool st = false; - return ASKDemod_ext(Cmd, verbose, emSearch, askType, &st); + 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 = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 45 || cmdp == 'h') return usage_data_rawdemod_am(); +static int Cmdaskmandemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 45 || cmdp == 'h') return usage_data_rawdemod_am(); - bool st = true; - if (Cmd[0] == 's') - return ASKDemod_ext(Cmd++, true, true, 1, &st); - else if (Cmd[1] == 's') - return ASKDemod_ext(Cmd += 2, true, true, 1, &st); + bool st = true; + if (Cmd[0] == 's') + return ASKDemod_ext(Cmd++, true, true, 1, &st); + else if (Cmd[1] == 's') + return ASKDemod_ext(Cmd += 2, true, true, 1, &st); - return ASKDemod(Cmd, true, true, 1); + return ASKDemod(Cmd, true, true, 1); } //by marshmellow //manchester decode //stricktly take 10 and 01 and convert to 0 and 1 -int Cmdmandecoderaw(const char *Cmd) { - size_t size = 0; - int high = 0, low = 0; - int i = 0, errCnt = 0, invert = 0, maxErr = 20; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 5 || cmdp == 'h') return usage_data_manrawdecode(); +static int Cmdmandecoderaw(const char *Cmd) { + size_t size = 0; + int high = 0, low = 0; + size_t i = 0; + uint16_t errCnt = 0; + int invert = 0, maxErr = 20; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 5 || cmdp == 'h') return usage_data_manrawdecode(); - if (DemodBufferLen == 0) return 0; - - uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; - - for (; i < DemodBufferLen; ++i){ - if (DemodBuffer[i] > high) - high = DemodBuffer[i]; - else if(DemodBuffer[i] < low) - low = DemodBuffer[i]; - bits[i] = DemodBuffer[i]; - } - - if (high > 7 || low < 0 ){ - PrintAndLogEx(WARNING, "Error: please raw demod the wave first then manchester raw decode"); - return 0; - } + if (DemodBufferLen == 0) return PM3_ESOFT; - sscanf(Cmd, "%i %i", &invert, &maxErr); - size = i; - uint8_t alignPos = 0; - errCnt = manrawdecode(bits, &size, invert, &alignPos); - if (errCnt >= maxErr){ - PrintAndLogEx(WARNING, "Too many errors: %d",errCnt); - return 0; - } - - PrintAndLogEx(NORMAL, "Manchester Decoded - # errors:%d - data:",errCnt); - PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, size, 16)); - - if (errCnt == 0){ - uint64_t id = 0; - uint32_t hi = 0; - size_t idx = 0; - if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1){ - //need to adjust to set bitstream back to manchester encoded data - //setDemodBuf(bits, size, idx); - printEM410x(hi, id); - } - } - return 1; + uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; + + for (; i < DemodBufferLen; ++i) { + if (DemodBuffer[i] > high) + high = DemodBuffer[i]; + else if (DemodBuffer[i] < low) + low = DemodBuffer[i]; + bits[i] = DemodBuffer[i]; + } + + if (high > 7 || low < 0) { + PrintAndLogEx(WARNING, "Error: please raw demod the wave first then manchester raw decode"); + return PM3_ESOFT; + } + + sscanf(Cmd, "%i %i", &invert, &maxErr); + size = i; + uint8_t alignPos = 0; + errCnt = manrawdecode(bits, &size, invert, &alignPos); + if (errCnt >= maxErr) { + PrintAndLogEx(WARNING, "Too many errors: %u", errCnt); + return PM3_ESOFT; + } + + PrintAndLogEx(NORMAL, "Manchester Decoded - # errors:%d - data:", errCnt); + PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, size, 32)); + + if (errCnt == 0) { + uint64_t id = 0; + uint32_t hi = 0; + size_t idx = 0; + if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) { + //need to adjust to set bitstream back to manchester encoded data + //setDemodBuff(bits, size, idx); + printEM410x(hi, id); + } + } + return PM3_SUCCESS; } -//by marshmellow -//biphase decode -//take 01 or 10 = 0 and 11 or 00 = 1 -//takes 2 arguments "offset" default = 0 if 1 it will shift the decode by one bit -// and "invert" default = 0 if 1 it will invert output -// the argument offset allows us to manually shift if the output is incorrect - [EDIT: now auto detects] -int CmdBiphaseDecodeRaw(const char *Cmd) { - size_t size = 0; - int offset = 0, invert = 0, maxErr = 20, errCnt = 0; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 3 || cmdp == 'h') return usage_data_biphaserawdecode(); +/* + * @author marshmellow + * biphase decode + * decodes 01 or 10 -> ZERO + * 11 or 00 -> ONE + * param offset adjust start position + * param invert invert output + * param masxErr maximum tolerated errors + */ +static int CmdBiphaseDecodeRaw(const char *Cmd) { + size_t size = 0; + int offset = 0, invert = 0, maxErr = 20, errCnt = 0; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 5 || cmdp == 'h') return usage_data_biphaserawdecode(); - sscanf(Cmd, "%i %i %i", &offset, &invert, &maxErr); - if (DemodBufferLen == 0){ - PrintAndLogEx(NORMAL, "DemodBuffer Empty - run 'data rawdemod ar' first"); - return 0; - } - - uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; - size = sizeof(bits); - if ( !getDemodBuf(bits, &size) ) return 0; - - errCnt = BiphaseRawDecode(bits, &size, &offset, invert); - if (errCnt < 0){ - PrintAndLogEx(WARNING, "Error during decode:%d", errCnt); - return 0; - } - if (errCnt > maxErr){ - PrintAndLogEx(WARNING, "Too many errors attempting to decode: %d",errCnt); - return 0; - } + sscanf(Cmd, "%i %i %i", &offset, &invert, &maxErr); + if (DemodBufferLen == 0) { + PrintAndLogEx(WARNING, "DemodBuffer Empty - run " _YELLOW_("'data rawdemod ar'")" first"); + return PM3_ESOFT; + } - if (errCnt > 0) - PrintAndLogEx(WARNING, "# Errors found during Demod (shown as 7 in bit stream): %d",errCnt); + uint8_t bits[MAX_DEMOD_BUF_LEN] = {0}; + size = sizeof(bits); + if (!getDemodBuff(bits, &size)) return PM3_ESOFT; - PrintAndLogEx(NORMAL, "Biphase Decoded using offset: %d - # invert:%d - data:",offset,invert); - PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, size, 16)); - - //remove first bit from raw demod - if (offset) - setDemodBuf(DemodBuffer,DemodBufferLen-offset, offset); - - setClockGrid(g_DemodClock, g_DemodStartIdx + g_DemodClock*offset/2); - return 1; + errCnt = BiphaseRawDecode(bits, &size, &offset, invert); + if (errCnt < 0) { + PrintAndLogEx(WARNING, "Error during decode:%d", errCnt); + return PM3_ESOFT; + } + if (errCnt > maxErr) { + PrintAndLogEx(WARNING, "Too many errors attempting to decode: %d", errCnt); + return PM3_ESOFT; + } + + if (errCnt > 0) + PrintAndLogEx(WARNING, "# Errors found during Demod (shown as " _YELLOW_("7")" in bit stream): %d", errCnt); + + PrintAndLogEx(NORMAL, "Biphase Decoded using offset: %d - # invert:%d - data:", offset, invert); + PrintAndLogEx(NORMAL, "%s", sprint_bin_break(bits, size, 32)); + + //remove first bit from raw demod + if (offset) + setDemodBuff(DemodBuffer, DemodBufferLen - offset, offset); + + setClockGrid(g_DemodClock, g_DemodStartIdx + g_DemodClock * offset / 2); + return PM3_SUCCESS; } //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=0; - sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); - - uint8_t BitStream[MAX_DEMOD_BUF_LEN]; - size_t size = getFromGraphBuf(BitStream); - if (size == 0 ) { - PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf"); - return 0; - } - 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 ) { - PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk); - return 0; - } +int ASKbiphaseDemod(const char *Cmd, bool verbose) { + //ask raw demod GraphBuffer first + int offset = 0, clk = 0, invert = 0, maxErr = 50; + sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); - //attempt to Biphase decode BitStream - errCnt = BiphaseRawDecode(BitStream, &size, &offset, invert); - if (errCnt < 0){ - if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt); - return 0; - } - if (errCnt > maxErr) { - if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: 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){ - PrintAndLogEx(NORMAL, "Biphase Decoded using offset: %d - clock: %d - # errors:%d - data:",offset,clk,errCnt); - printDemodBuff(); - } - return 1; + uint8_t BitStream[MAX_DEMOD_BUF_LEN]; + size_t size = getFromGraphBuf(BitStream); + if (size == 0) { + PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf"); + return PM3_ESOFT; + } + 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) { + PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk); + return PM3_ESOFT; + } + + //attempt to Biphase decode BitStream + errCnt = BiphaseRawDecode(BitStream, &size, &offset, invert); + if (errCnt < 0) { + if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt); + return PM3_ESOFT; + } + if (errCnt > maxErr) { + if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode too many errors: %d", errCnt); + return PM3_ESOFT; + } + + //success set DemodBuffer and return + setDemodBuff(BitStream, size, 0); + setClockGrid(clk, startIdx + clk * offset / 2); + if (g_debugMode || verbose) { + PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2)); + printDemodBuff(); + } + return PM3_SUCCESS; } //by marshmellow - see ASKbiphaseDemod -int Cmdaskbiphdemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') return usage_data_rawdemod_ab(); +static int Cmdaskbiphdemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 25 || cmdp == 'h') return usage_data_rawdemod_ab(); - return ASKbiphaseDemod(Cmd, true); + return ASKbiphaseDemod(Cmd, true); } //by marshmellow - see ASKDemod -int Cmdaskrawdemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') return usage_data_rawdemod_ar(); - - return ASKDemod(Cmd, true, false, 0); +static int Cmdaskrawdemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 25 || cmdp == 'h') return usage_data_rawdemod_ar(); + + return ASKDemod(Cmd, true, false, 0); } -int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph, bool verbose) { - // sanity check - if ( window > len ) window = len; - - if (verbose) PrintAndLogEx(INFO, "performing %d correlations", GraphTraceLen - window); - - //test - double autocv = 0.0; // Autocovariance value - double ac_value; // Computed autocorrelation value to be returned - double variance; // Computed variance - double mean; - size_t correlation = 0; - int lastmax = 0; - - // in, len, 4000 - mean = compute_mean(in, len); - variance = compute_variance(in, len); - - static int CorrelBuffer[MAX_GRAPH_TRACE_LEN]; - - for (int i = 0; i < len - window; ++i) { +int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveGrph, bool verbose) { + // sanity check + if (window > len) window = len; - for (size_t j=0; j < (len - i); j++) { - autocv += (in[j] - mean) * (in[j+i] - mean); - } - autocv = (1.0 / (len - i)) * autocv; + if (verbose) PrintAndLogEx(INFO, "performing " _YELLOW_("%d")" correlations", GraphTraceLen - window); - CorrelBuffer[i] = autocv; - - // Autocorrelation is autocovariance divided by variance - ac_value = autocv / variance; + //test + double autocv = 0.0; // Autocovariance value + size_t correlation = 0; + int lastmax = 0; - // keep track of which distance is repeating. - if ( ac_value > 1) { - correlation = i-lastmax; - lastmax = i; - } - } + // in, len, 4000 + double mean = compute_mean(in, len); + // Computed variance + double variance = compute_variance(in, len); - if (verbose && ( correlation > 1 ) ) { - PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation); - } else { - PrintAndLogEx(FAILED, "no repeating pattern found"); - } - - if (SaveGrph){ - //GraphTraceLen = GraphTraceLen - window; - memcpy(out, CorrelBuffer, len * sizeof(int)); - RepaintGraphWindow(); - } - return correlation; + static int CorrelBuffer[MAX_GRAPH_TRACE_LEN]; + + for (size_t i = 0; i < len - window; ++i) { + + for (size_t j = 0; j < (len - i); j++) { + autocv += (in[j] - mean) * (in[j + i] - mean); + } + autocv = (1.0 / (len - i)) * autocv; + + CorrelBuffer[i] = autocv; + + // Computed autocorrelation value to be returned + // Autocorrelation is autocovariance divided by variance + double ac_value = autocv / variance; + + // keep track of which distance is repeating. + if (ac_value > 1) { + correlation = i - lastmax; + lastmax = i; + } + } + + // + int hi = 0, idx = 0; + int distance = 0, hi_1 = 0, idx_1 = 0; + for (size_t i = 0; i <= len; ++i) { + if (CorrelBuffer[i] > hi) { + hi = CorrelBuffer[i]; + idx = i; + } + } + + for (size_t i = idx + 1; i <= window; ++i) { + if (CorrelBuffer[i] > hi_1) { + hi_1 = CorrelBuffer[i]; + idx_1 = i; + } + } + + int foo = ABS(hi - hi_1); + int bar = (int)((int)((hi + hi_1) / 2) * 0.04); + + if (verbose && foo < bar) { + distance = idx_1 - idx; + PrintAndLogEx(SUCCESS, "possible 4% visible correlation %4d samples", distance); + } else if (verbose && (correlation > 1)) { + PrintAndLogEx(SUCCESS, "possible correlation %4d samples", correlation); + } else { + PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size"); + } + + int retval = correlation; + if (SaveGrph) { + //GraphTraceLen = GraphTraceLen - window; + memcpy(out, CorrelBuffer, len * sizeof(int)); + if (distance > 0) { + setClockGrid(distance, idx); + retval = distance; + } else + setClockGrid(correlation, idx); + + CursorCPos = idx_1; + CursorDPos = idx_1 + retval; + DemodBufferLen = 0; + RepaintGraphWindow(); + } + + return retval; } -int CmdAutoCorr(const char *Cmd) { +static int CmdAutoCorr(const char *Cmd) { - uint32_t window = 4000; - uint8_t cmdp = 0; - bool updateGrph = false; - bool errors = false; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_data_autocorr(); - case 'g': - updateGrph = true; - cmdp++; - break; - case 'w': - window = param_get32ex(Cmd, cmdp+1, 4000, 10); - if (window >= GraphTraceLen) { - PrintAndLogEx(WARNING, "window must be smaller than trace (%d samples)", GraphTraceLen); - errors = true; - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0 ) return usage_data_autocorr(); - - return AutoCorrelate(GraphBuffer, GraphBuffer, GraphTraceLen, window, updateGrph, true); + uint32_t window = 4000; + uint8_t cmdp = 0; + bool updateGrph = false; + bool errors = false; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_data_autocorr(); + case 'g': + updateGrph = true; + cmdp++; + break; + case 'w': + window = param_get32ex(Cmd, cmdp + 1, 4000, 10); + if (window >= GraphTraceLen) { + PrintAndLogEx(WARNING, "window must be smaller than trace (%d samples)", GraphTraceLen); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || cmdp == 0) return usage_data_autocorr(); + + AutoCorrelate(GraphBuffer, GraphBuffer, GraphTraceLen, window, updateGrph, true); + + return PM3_SUCCESS; } -int CmdBitsamples(const char *Cmd) -{ - int cnt = 0; - uint8_t got[12288]; +static int CmdBitsamples(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + int cnt = 0; + uint8_t got[12288]; - if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 2500 , false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return 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; + if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + } + + for (size_t j = 0; j < sizeof(got); j++) { + for (uint8_t k = 0; k < 8; k++) { + if (got[j] & (1 << (7 - k))) + GraphBuffer[cnt++] = 1; + else + GraphBuffer[cnt++] = 0; + } + } + GraphTraceLen = cnt; + RepaintGraphWindow(); + return PM3_SUCCESS; } -int CmdBuffClear(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_data_buffclear(); - - UsbCommand c = {CMD_BUFF_CLEAR, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - ClearGraph(true); - return 0; +static int CmdBuffClear(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_data_buffclear(); + + clearCommandBuffer(); + SendCommandNG(CMD_BUFF_CLEAR, NULL, 0); + ClearGraph(true); + return PM3_SUCCESS; } -int CmdDec(const char *Cmd) -{ - for (int i = 0; i < (GraphTraceLen / 2); ++i) - GraphBuffer[i] = GraphBuffer[i * 2]; - GraphTraceLen /= 2; - PrintAndLogEx(NORMAL, "decimated by 2"); - RepaintGraphWindow(); - return 0; +static int CmdDec(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + for (size_t i = 0; i < (GraphTraceLen / 2); ++i) + GraphBuffer[i] = GraphBuffer[i * 2]; + GraphTraceLen /= 2; + PrintAndLogEx(NORMAL, "decimated by 2"); + RepaintGraphWindow(); + return PM3_SUCCESS; } /** * Undecimate - I'd call it 'interpolate', but we'll save that @@ -855,357 +909,374 @@ int CmdDec(const char *Cmd) * @param Cmd * @return */ -int CmdUndec(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_data_undecimate(); +static int CmdUndec(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_data_undecimate(); - uint8_t factor = param_get8ex(Cmd, 0, 2, 10); + 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++; - } + //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; + memcpy(GraphBuffer, swap, s_index * sizeof(int)); + GraphTraceLen = s_index; + RepaintGraphWindow(); + return PM3_SUCCESS; } //by marshmellow //shift graph zero up or down based on input + or - -int CmdGraphShiftZero(const char *Cmd) { - int shift = 0, shiftedVal = 0; - //set options from parameters entered with the command - sscanf(Cmd, "%i", &shift); +static int CmdGraphShiftZero(const char *Cmd) { + int shift = 0; + //set options from parameters entered with the command + sscanf(Cmd, "%i", &shift); - for(int i = 0; i < GraphTraceLen; i++){ - if ( i+shift >= GraphTraceLen) - shiftedVal = GraphBuffer[i]; - else - shiftedVal = GraphBuffer[i] + shift; - - if (shiftedVal > 127) - shiftedVal = 127; - else if (shiftedVal < -127) - shiftedVal = -127; - GraphBuffer[i] = shiftedVal; - } - CmdNorm(""); - return 0; + for (size_t i = 0; i < GraphTraceLen; i++) { + int shiftedVal = GraphBuffer[i] + shift; + + if (shiftedVal > 127) + shiftedVal = 127; + else if (shiftedVal < -127) + shiftedVal = -127; + GraphBuffer[i] = shiftedVal; + } + CmdNorm(""); + return PM3_SUCCESS; } 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; + int last = 0; + for (int i = 1; i < len; i++) { + if (in[i] - in[i - 1] >= 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 PM3_SUCCESS; } //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 +//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); +static int CmdAskEdgeDetect(const char *Cmd) { + int thresLen = 25; + int ans = 0; + sscanf(Cmd, "%i", &thresLen); - ans = AskEdgeDetect(GraphBuffer, GraphBuffer, GraphTraceLen, thresLen); - RepaintGraphWindow(); - return ans; + ans = AskEdgeDetect(GraphBuffer, GraphBuffer, GraphTraceLen, thresLen); + RepaintGraphWindow(); + return ans; } /* 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') - return usage_data_detectclock(); +static int CmdDetectClockRate(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 6 || strlen(Cmd) == 0 || cmdp == 'h') + return usage_data_detectclock(); - int clock = 0; - switch ( tolower(cmdp) ) { - case 'a' : - clock = GetAskClock(Cmd+1, true); - break; - case 'f' : - clock = GetFskClock("", true); - break; - case 'n' : - clock = GetNrzClock("", true); - break; - case 'p' : - clock = GetPskClock("", true); - break; - default : - PrintAndLogEx(NORMAL, "Please specify a valid modulation to detect the clock of - see option h for help"); - break; - } - RepaintGraphWindow(); - return clock; + int clock1 = 0; + switch (cmdp) { + case 'a' : + clock1 = GetAskClock(Cmd + 1, true); + break; + case 'f' : + clock1 = GetFskClock("", true); + break; + case 'n' : + clock1 = GetNrzClock("", true); + break; + case 'p' : + clock1 = GetPskClock("", true); + break; + default : + PrintAndLogEx(NORMAL, "Please specify a valid modulation to detect the clock of - see option h for help"); + break; + } + RepaintGraphWindow(); + return clock1; } -char *GetFSKType(uint8_t fchigh, uint8_t fclow, uint8_t invert) -{ - 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 char *GetFSKType(uint8_t fchigh, uint8_t fclow, uint8_t invert) { + static char fType[8]; + memset(fType, 0x00, 8); + char *fskType = fType; + + if (fchigh == 10 && fclow == 8) { + + if (invert) + memcpy(fskType, "FSK2a", 5); + else + 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; } //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; +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); - if (strlen(Cmd)>0 && strlen(Cmd)<=2) { - if (rfLen==1) { - invert = 1; //if invert option only is used - rfLen = 0; - } - } + //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); - 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); + if (strlen(Cmd) > 0 && strlen(Cmd) <= 2) { + if (rfLen == 1) { + invert = 1; //if invert option only is used + rfLen = 0; + } + } - // Now output the bitstream to the scrollback by line of 16 bits - if (verbose || g_debugMode) { - PrintAndLogEx(DEBUG, "DEBUG: (FSKrawDemod) Using Clock:%u, invert:%u, fchigh:%u, fclow:%u", rfLen, invert, fchigh, fclow); - PrintAndLogEx(NORMAL, "%s decoded bitstream:", GetFSKType(fchigh, fclow, invert)); - printDemodBuff(); - } - return 1; - } else { - if (g_debugMode) PrintAndLogEx(NORMAL, "no FSK data found"); - } - return 0; + if (getSignalProperties()->isnoise) + return PM3_ESOFT; + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; + size_t BitLen = getFromGraphBuf(bits); + if (BitLen == 0) return PM3_ESOFT; + + //get field clock lengths + if (!fchigh || !fclow) { + uint16_t fcs = countFC(bits, BitLen, true); + 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(bits, BitLen, fchigh, fclow, &firstClockEdge); + if (!rfLen) rfLen = 50; + } + int startIdx = 0; + int size = fskdemod(bits, BitLen, rfLen, invert, fchigh, fclow, &startIdx); + if (size > 0) { + setDemodBuff(bits, size, 0); + setClockGrid(rfLen, startIdx); + + // Now output the bitstream to the scrollback by line of 16 bits + if (verbose || g_debugMode) { + PrintAndLogEx(DEBUG, "DEBUG: (FSKrawDemod) Using Clock:%u, invert:%u, fchigh:%u, fclow:%u", rfLen, invert, fchigh, fclow); + PrintAndLogEx(NORMAL, "%s decoded bitstream:", GetFSKType(fchigh, fclow, invert)); + printDemodBuff(); + } + return PM3_SUCCESS; + } else { + PrintAndLogEx(DEBUG, "no FSK data found"); + } + return PM3_SUCCESS; } //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 = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 20 || cmdp == 'h') return usage_data_rawdemod_fs(); +static int CmdFSKrawdemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 20 || cmdp == 'h') return usage_data_rawdemod_fs(); - return FSKrawDemod(Cmd, true); + return FSKrawDemod(Cmd, true); } //by marshmellow //attempt to psk1 demod graph buffer int PSKDemod(const char *Cmd, bool verbose) { - int invert = 0, clk = 0, 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) PrintAndLogEx(WARNING, "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) PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) 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) PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, BitLen, errCnt); - return 0; - } - if (verbose || g_debugMode){ - PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) Using Clock:%d, invert:%d, Bits Found:%d",clk, invert, BitLen); - if (errCnt > 0){ - PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) errors during Demoding (shown as 7 in bit stream): %d", errCnt); - } - } - //prime demod buffer for output - setDemodBuf(BitStream, BitLen, 0); - setClockGrid(clk, startIdx); - return 1; + int invert = 0, clk = 0, 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) PrintAndLogEx(WARNING, "Invalid argument: %s", Cmd); + return PM3_EINVARG; + } + + if (getSignalProperties()->isnoise) + return PM3_ESOFT; + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; + size_t bitlen = getFromGraphBuf(bits); + if (bitlen == 0) + return PM3_ESOFT; + + int startIdx = 0; + int errCnt = pskRawDemod_ext(bits, &bitlen, &clk, &invert, &startIdx); + if (errCnt > maxErr) { + if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, bitlen, errCnt); + return PM3_ESOFT; + } + if (errCnt < 0 || bitlen < 16) { //throw away static - allow 1 and -1 (in case of threshold command first) + if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, bitlen, errCnt); + return PM3_ESOFT; + } + if (verbose || g_debugMode) { + PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) Using Clock:%d, invert:%d, Bits Found:%d", clk, invert, bitlen); + if (errCnt > 0) { + PrintAndLogEx(DEBUG, "DEBUG: (PSKdemod) errors during Demoding (shown as 7 in bit stream): %d", errCnt); + } + } + //prime demod buffer for output + setDemodBuff(bits, bitlen, 0); + setClockGrid(clk, startIdx); + return PM3_SUCCESS; } -int CmdPSKIdteck(const char *Cmd) { +static int CmdIdteckDemod(const char *Cmd) { + (void)Cmd; // Cmd is not used so far - if (!PSKDemod("", false)) { - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck PSKDemod failed"); - return 0; - } - size_t size = DemodBufferLen; + if (PSKDemod("", false) != PM3_SUCCESS) { + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck PSKDemod failed"); + return PM3_ESOFT; + } + size_t size = DemodBufferLen; - //get binary from PSK1 wave - int idx = detectIdteck(DemodBuffer, &size); - if (idx < 0){ + //get binary from PSK1 wave + int idx = detectIdteck(DemodBuffer, &size); + if (idx < 0) { - if (idx == -1) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: not enough samples"); - else if (idx == -2) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: just noise"); - else if (idx == -3) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: preamble not found"); - else if (idx == -4) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: size not correct: %d", size); - else - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: idx: %d",idx); - - // if didn't find preamble try again inverting - if (!PSKDemod("1", false)) { - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck PSKDemod failed"); - return 0; - } - idx = detectIdteck(DemodBuffer, &size); - if (idx < 0){ - - if (idx == -1) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: not enough samples"); - else if (idx == -2) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: just noise"); - else if (idx == -3) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: preamble not found"); - else if (idx == -4) - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: size not correct: %d", size); - else - PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: idx: %d",idx); + if (idx == -1) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: not enough samples"); + else if (idx == -2) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: just noise"); + else if (idx == -3) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: preamble not found"); + else if (idx == -4) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: size not correct: %d", size); + else + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: idx: %d", idx); - return 0; - } - } - setDemodBuf(DemodBuffer, 64, idx); - - //got a good demod - uint32_t id = 0; - uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32); - uint32_t raw2 = bytebits_to_byte(DemodBuffer+32, 32); - - //parity check (TBD) - //checksum check (TBD) + // if didn't find preamble try again inverting + if (PSKDemod("1", false) != PM3_SUCCESS) { + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck PSKDemod failed"); + return PM3_ESOFT; + } + idx = detectIdteck(DemodBuffer, &size); + if (idx < 0) { - //output - PrintAndLogEx(SUCCESS, "IDTECK Tag Found: Card ID %u , Raw: %08X%08X", id, raw1, raw2); - return 1; + if (idx == -1) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: not enough samples"); + else if (idx == -2) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: just noise"); + else if (idx == -3) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: preamble not found"); + else if (idx == -4) + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: size not correct: %d", size); + else + PrintAndLogEx(DEBUG, "DEBUG: Error - Idteck: idx: %d", idx); + + return PM3_ESOFT; + } + } + setDemodBuff(DemodBuffer, 64, idx); + + //got a good demod + uint32_t id = 0; + uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32); + uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); + + //parity check (TBD) + //checksum check (TBD) + + //output + PrintAndLogEx(SUCCESS, "IDTECK Tag Found: Card ID %u , Raw: %08X%08X", id, raw1, raw2); + return PM3_SUCCESS; } +int demodIdteck(void) { + return CmdIdteckDemod(""); +} + + // 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 errCnt = 0, clkStartIdx = 0; - int invert = 0, clk = 0, maxErr = 100; - sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); - if (clk == 1){ - invert = 1; - clk = 0; - } - - if (invert != 0 && invert != 1) { - PrintAndLogEx(WARNING, "(NRZrawDemod) Invalid argument: %s", Cmd); - return 0; - } - - uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; - size_t BitLen = getFromGraphBuf(bits); - - if (BitLen == 0) return 0; - - errCnt = nrzRawDemod(bits, &BitLen, &clk, &invert, &clkStartIdx); - if (errCnt > maxErr){ - PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) 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) - PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, BitLen, errCnt); - return 0; - } - if (verbose || g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) Tried NRZ Demod using Clock: %d - invert: %d - Bits Found: %d", clk, invert, BitLen); - //prime demod buffer for output - setDemodBuf(bits, BitLen, 0); - setClockGrid(clk, clkStartIdx); + int errCnt = 0, clkStartIdx = 0; + int invert = 0, clk = 0, maxErr = 100; + sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); + if (clk == 1) { + invert = 1; + clk = 0; + } + + if (invert != 0 && invert != 1) { + PrintAndLogEx(WARNING, "(NRZrawDemod) Invalid argument: %s", Cmd); + return PM3_EINVARG; + } + + if (getSignalProperties()->isnoise) + return PM3_ESOFT; + + uint8_t bits[MAX_GRAPH_TRACE_LEN] = {0}; + size_t BitLen = getFromGraphBuf(bits); + + if (BitLen == 0) return PM3_ESOFT; + + errCnt = nrzRawDemod(bits, &BitLen, &clk, &invert, &clkStartIdx); + if (errCnt > maxErr) { + PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, BitLen, errCnt); + return PM3_ESOFT; + } + if (errCnt < 0 || BitLen < 16) { //throw away static - allow 1 and -1 (in case of threshold command first) + PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d", clk, invert, BitLen, errCnt); + return PM3_ESOFT; + } + if (verbose || g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) Tried NRZ Demod using Clock: %d - invert: %d - Bits Found: %d", clk, invert, BitLen); + //prime demod buffer for output + setDemodBuff(bits, BitLen, 0); + setClockGrid(clk, clkStartIdx); - if (errCnt > 0 && (verbose || g_debugMode)) PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) Errors during Demoding (shown as 7 in bit stream): %d", errCnt); - if (verbose || g_debugMode) { - PrintAndLogEx(NORMAL, "NRZ demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - } - return 1; + if (errCnt > 0 && (verbose || g_debugMode)) PrintAndLogEx(DEBUG, "DEBUG: (NRZrawDemod) Errors during Demoding (shown as 7 in bit stream): %d", errCnt); + if (verbose || g_debugMode) { + PrintAndLogEx(NORMAL, "NRZ demoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printDemodBuff(); + } + return PM3_SUCCESS; } -int CmdNRZrawDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_nr(); +static int CmdNRZrawDemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_nr(); - return NRZrawDemod(Cmd, true); + return NRZrawDemod(Cmd, true); } // by marshmellow @@ -1213,543 +1284,575 @@ int CmdNRZrawDemod(const char *Cmd) { // attempts to demodulate psk only // prints binary found and saves in demodbuffer for further commands int CmdPSK1rawDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p1(); - int ans = PSKDemod(Cmd, true); - //output - if (!ans){ - if (g_debugMode) PrintAndLogEx(WARNING, "Error demoding: %d",ans); - return 0; - } - PrintAndLogEx(NORMAL, "PSK1 demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - return 1; + int ans = PSKDemod(Cmd, true); + //output + if (ans != PM3_SUCCESS) { + if (g_debugMode) PrintAndLogEx(WARNING, "Error demoding: %d", ans); + return PM3_ESOFT; + } + PrintAndLogEx(NORMAL, "PSK1 demoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printDemodBuff(); + return PM3_SUCCESS; } // by marshmellow // takes same args as cmdpsk1rawdemod -int CmdPSK2rawDemod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p2(); +static int CmdPSK2rawDemod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) > 16 || cmdp == 'h') return usage_data_rawdemod_p2(); - int ans = PSKDemod(Cmd, true); - if (!ans){ - if (g_debugMode) PrintAndLogEx(WARNING, "Error demoding: %d",ans); - return 0; - } - psk1TOpsk2(DemodBuffer, DemodBufferLen); - PrintAndLogEx(NORMAL, "PSK2 demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - return 1; + int ans = PSKDemod(Cmd, true); + if (ans != PM3_SUCCESS) { + if (g_debugMode) PrintAndLogEx(WARNING, "Error demoding: %d", ans); + return PM3_ESOFT; + } + psk1TOpsk2(DemodBuffer, DemodBufferLen); + PrintAndLogEx(NORMAL, "PSK2 demoded bitstream:"); + // Now output the bitstream to the scrollback by line of 16 bits + printDemodBuff(); + return PM3_SUCCESS; } // by marshmellow - combines all raw demod functions into one menu command -int CmdRawDemod(const char *Cmd) { - int ans = 0; +static int CmdRawDemod(const char *Cmd) { + int ans = 0; - if (strlen(Cmd) > 35 || strlen(Cmd) < 2) - return usage_data_rawdemod(); - - str_lower( (char *)Cmd); + if (strlen(Cmd) > 35 || strlen(Cmd) < 2) + return usage_data_rawdemod(); - if (str_startswith(Cmd, "fs")) ans = CmdFSKrawdemod(Cmd+2); - else if(str_startswith(Cmd, "ab")) ans = Cmdaskbiphdemod(Cmd+2); - else if(str_startswith(Cmd, "am")) ans = Cmdaskmandemod(Cmd+2); - else if(str_startswith(Cmd, "ar")) ans = Cmdaskrawdemod(Cmd+2); - else if(str_startswith(Cmd, "nr")) ans = CmdNRZrawDemod(Cmd+2); - else if(str_startswith(Cmd, "p1")) ans = CmdPSK1rawDemod(Cmd+2); - else if(str_startswith(Cmd, "p2")) ans = CmdPSK2rawDemod(Cmd+2); - else PrintAndLogEx(WARNING, "Unknown modulation entered - see help ('h') for parameter structure"); + str_lower((char *)Cmd); - return ans; + if (str_startswith(Cmd, "fs") || Cmd[0] == 'f') ans = CmdFSKrawdemod(Cmd + 2); + else if (str_startswith(Cmd, "ab")) ans = Cmdaskbiphdemod(Cmd + 2); + else if (str_startswith(Cmd, "am")) ans = Cmdaskmandemod(Cmd + 2); + else if (str_startswith(Cmd, "ar")) ans = Cmdaskrawdemod(Cmd + 2); + else if (str_startswith(Cmd, "nr") || Cmd[0] == 'n') ans = CmdNRZrawDemod(Cmd + 2); + else if (str_startswith(Cmd, "p1") || Cmd[0] == 'p') ans = CmdPSK1rawDemod(Cmd + 2); + else if (str_startswith(Cmd, "p2")) ans = CmdPSK2rawDemod(Cmd + 2); + else PrintAndLogEx(WARNING, "Unknown modulation entered - see help ('h') for parameter structure"); + + return ans; } -void setClockGrid(int clk, int offset) { - g_DemodStartIdx = offset; - g_DemodClock = clk; - PrintAndLogEx(DEBUG, "DEBUG: (setClockGrid) demodoffset %d, clk %d", offset, clk); +void setClockGrid(uint32_t clk, int offset) { + g_DemodStartIdx = offset; + g_DemodClock = clk; + if (clk == 0 && offset == 0) + PrintAndLogEx(DEBUG, "DEBUG: (setClockGrid) clear settings"); + else + PrintAndLogEx(DEBUG, "DEBUG: (setClockGrid) demodoffset %d, clk %d", offset, clk); - if (offset > clk) offset %= clk; - if (offset < 0) 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(); - } + 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(); + } } int CmdGrid(const char *Cmd) { - sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); - PlotGridXdefault = PlotGridX; - PlotGridYdefault = PlotGridY; - RepaintGraphWindow(); - return 0; + sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); + PlotGridXdefault = PlotGridX; + PlotGridYdefault = PlotGridY; + RepaintGraphWindow(); + return PM3_SUCCESS; } -int CmdSetGraphMarkers(const char *Cmd) { - sscanf(Cmd, "%i %i", &CursorCPos, &CursorDPos); - RepaintGraphWindow(); - return 0; +static int CmdSetGraphMarkers(const char *Cmd) { + sscanf(Cmd, "%i %i", &CursorCPos, &CursorDPos); + RepaintGraphWindow(); + return PM3_SUCCESS; } -int CmdHexsamples(const char *Cmd) { - int i, j, requested = 0, offset = 0; - char string_buf[25]; - char* string_ptr = string_buf; - uint8_t got[BIGBUF_SIZE]; +static int CmdHexsamples(const char *Cmd) { + uint32_t requested = 0; + uint32_t offset = 0; + char string_buf[25]; + char *string_ptr = string_buf; + uint8_t got[BIGBUF_SIZE]; - sscanf(Cmd, "%i %i", &requested, &offset); + sscanf(Cmd, "%u %u", &requested, &offset); - /* if no args send something */ - if (requested == 0) - requested = 8; - - if (offset + requested > sizeof(got)) { - PrintAndLogEx(NORMAL, "Tried to read past end of buffer, + > %d", BIGBUF_SIZE); - return 0; - } + /* if no args send something */ + if (requested == 0) + requested = 8; - if ( !GetFromDevice(BIG_BUF, got, requested, offset, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return 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 - PrintAndLogEx(NORMAL, "%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'; - PrintAndLogEx(NORMAL, "%s", string_buf); - string_buf[0] = '\0'; - } - } - return 0; + if (offset + requested > sizeof(got)) { + PrintAndLogEx(NORMAL, "Tried to read past end of buffer, + > %d", BIGBUF_SIZE); + return PM3_EINVARG; + } + + if (!GetFromDevice(BIG_BUF, got, requested, offset, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ESOFT; + } + + uint8_t i = 0; + for (uint32_t 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 + PrintAndLogEx(NORMAL, "%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'; + PrintAndLogEx(NORMAL, "%s", string_buf); + string_buf[0] = '\0'; + } + } + return PM3_SUCCESS; } -int CmdHide(const char *Cmd) { - HideGraphWindow(); - return 0; +static int CmdHide(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + HideGraphWindow(); + return PM3_SUCCESS; } //zero mean GraphBuffer int CmdHpf(const char *Cmd) { - int i, accum = 0; + (void)Cmd; // Cmd is not used so far + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + removeSignalOffset(bits, size); + // push it back to graph + setGraphBuf(bits, size); + // set signal properties low/high/mean/amplitude and is_noise detection + computeSignalProperties(bits, size); - for (i = 10; i < GraphTraceLen; ++i) - accum += GraphBuffer[i]; - - accum /= (GraphTraceLen - 10); - - for (i = 0; i < GraphTraceLen; ++i) - GraphBuffer[i] -= accum; - - RepaintGraphWindow(); - return 0; + RepaintGraphWindow(); + return PM3_SUCCESS; } -bool _headBit( BitstreamOut *stream) { - int bytepos = stream->position >> 3; // divide by 8 - int bitpos = (stream->position++) & 7; // mask out 00000111 - return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; +static bool _headBit(BitstreamOut *stream) { + int bytepos = stream->position >> 3; // divide by 8 + int bitpos = (stream->position++) & 7; // mask out 00000111 + return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1; } -uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b) { - uint8_t val = 0; - for(int i = 0 ; i < bits_per_sample; i++) - val |= (_headBit(b) << (7-i)); +static uint8_t getByte(uint8_t bits_per_sample, BitstreamOut *b) { + uint8_t val = 0; + for (int i = 0 ; i < bits_per_sample; i++) + val |= (_headBit(b) << (7 - i)); - return val; + 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 }; +int getSamples(uint32_t 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 (n == 0 || n > sizeof(got)) + n = sizeof(got); - if (!silent) PrintAndLogEx(NORMAL, "Reading %d bytes from device memory\n", n); + if (!silent) PrintAndLogEx(NORMAL, "Reading %d bytes from device memory\n", n); - UsbCommand response; - if ( !GetFromDevice(BIG_BUF, got, n, 0, &response, 10000, true) ) { + PacketResponseNG response; + if (!GetFromDevice(BIG_BUF, got, n, 0, &response, 10000, true)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; + return PM3_ETIMEOUT; } - if (!silent) PrintAndLogEx(NORMAL, "Data fetched"); - - uint8_t bits_per_sample = 8; + if (!silent) PrintAndLogEx(NORMAL, "Data fetched"); - //Old devices without this feature would send 0 at arg[0] - if (response.arg[0] > 0) { - sample_config *sc = (sample_config *) response.d.asBytes; - if (!silent) PrintAndLogEx(NORMAL, "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) PrintAndLogEx(NORMAL, "Unpacking..."); - - BitstreamOut 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; - - if (!silent) PrintAndLogEx(NORMAL, "Unpacked %d samples" , j ); - } else { - for (int j = 0; j < n; j++) { - GraphBuffer[j] = ((int)got[j]) - 128; - } - GraphTraceLen = n; - } + uint8_t bits_per_sample = 8; -//ICEMAN todo - // set signal properties low/high/mean/amplitude and is_noice detection - justNoise(GraphBuffer, GraphTraceLen); - - setClockGrid(0, 0); - DemodBufferLen = 0; - RepaintGraphWindow(); - return 0; + //Old devices without this feature would send 0 at arg[0] + if (response.oldarg[0] > 0) { + sample_config *sc = (sample_config *) response.data.asBytes; + if (!silent) PrintAndLogEx(NORMAL, "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) PrintAndLogEx(NORMAL, "Unpacking..."); + + BitstreamOut 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) - 127; + } + GraphTraceLen = j; + + if (!silent) PrintAndLogEx(NORMAL, "Unpacked %d samples", j); + + } else { + for (int j = 0; j < n; j++) { + GraphBuffer[j] = ((int)got[j]) - 127; + } + GraphTraceLen = n; + } + + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + // set signal properties low/high/mean/amplitude and is_noise detection + computeSignalProperties(bits, size); + + setClockGrid(0, 0); + DemodBufferLen = 0; + RepaintGraphWindow(); + return PM3_SUCCESS; } -int CmdSamples(const char *Cmd) { - int n = strtol(Cmd, NULL, 0); - return getSamples(n, false); +static int CmdSamples(const char *Cmd) { + int n = strtol(Cmd, NULL, 0); + return getSamples(n, false); } int CmdTuneSamples(const char *Cmd) { -#define NON_VOLTAGE 1000 -#define LF_UNUSABLE_V 2000 -#define LF_MARGINAL_V 10000 -#define HF_UNUSABLE_V 3000 -#define HF_MARGINAL_V 5000 -#define ANTENNA_ERROR 1.03 // current algo has 3% error margin. - int timeout = 0; - PrintAndLogEx(INFO, "\nmeasuring antenna characteristics, please wait..."); + (void)Cmd; // Cmd is not used so far +#define NON_VOLTAGE 1000 +#define LF_UNUSABLE_V 2000 +#define LF_MARGINAL_V 10000 +#define HF_UNUSABLE_V 3000 +#define HF_MARGINAL_V 5000 +#define ANTENNA_ERROR 1.03 // current algo has 3% error margin. - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - while (!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING, &resp, 2000)) { - timeout++; - printf("."); fflush(stdout); - if (timeout > 7) { - PrintAndLogEx(WARNING, "\nno response from Proxmark. Aborting..."); - return 1; - } - } - PrintAndLogEx(NORMAL, "\n"); - - uint32_t v_lf125 = resp.arg[0]; - uint32_t v_lf134 = resp.arg[0] >> 32; - - uint32_t v_hf = resp.arg[1]; - uint32_t peakf = resp.arg[2]; - uint32_t peakv = resp.arg[2] >> 32; - - if ( v_lf125 > NON_VOLTAGE ) - PrintAndLogEx(SUCCESS, "LF antenna: %5.2f V - 125.00 kHz", (v_lf125 * ANTENNA_ERROR)/1000.0); - if ( v_lf134 > NON_VOLTAGE ) - PrintAndLogEx(SUCCESS, "LF antenna: %5.2f V - 134.00 kHz", (v_lf134 * ANTENNA_ERROR)/1000.0); - if ( peakv > NON_VOLTAGE && peakf > 0 ) - PrintAndLogEx(SUCCESS, "LF optimal: %5.2f V - %6.2f kHz", (peakv * ANTENNA_ERROR)/1000.0, 12000.0/(peakf+1)); + // hide demod plot line + DemodBufferLen = 0; + setClockGrid(0, 0); + RepaintGraphWindow(); - char judgement[20]; - memset(judgement, 0, sizeof(judgement)); - // LF evaluation - if (peakv < LF_UNUSABLE_V) - sprintf(judgement, _RED_(UNUSABLE) ); - else if (peakv < LF_MARGINAL_V) - sprintf(judgement, _YELLOW_(MARGINAL) ); - else - sprintf(judgement, _GREEN_(OK) ); - - PrintAndLogEx(NORMAL, "%sLF antenna is %s \n" - , (peakv < LF_UNUSABLE_V) ? _CYAN_([!]) : _GREEN_([+]) - , judgement - ); - - // HF evaluation - if ( v_hf > NON_VOLTAGE ) - PrintAndLogEx(SUCCESS, "HF antenna: %5.2f V - 13.56 MHz", (v_hf * ANTENNA_ERROR)/1000.0); - memset(judgement, 0, sizeof(judgement)); - - if (v_hf < HF_UNUSABLE_V) - sprintf(judgement, _RED_(UNUSABLE) ); - else if (v_hf < HF_MARGINAL_V) - sprintf(judgement, _YELLOW_(MARGINAL) ); - else - sprintf(judgement, _GREEN_(OK) ); - - PrintAndLogEx(NORMAL, "%sHF antenna is %s" - , (v_hf < HF_UNUSABLE_V) ? _CYAN_([!]) : _GREEN_([+]) - , judgement - ); + int timeout = 0; + PrintAndLogEx(INFO, "\nMeasuring antenna characteristics, please wait..."); - // graph LF measurements - // even here, these values has 3% error. - uint16_t test = 0; - for (int i = 0; i < 256; i++) { - GraphBuffer[i] = resp.d.asBytes[i] - 128; - test += resp.d.asBytes[i]; - } - if ( test > 0 ) { - PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor 89 is 134khz, 95 is 125khz.\n\n"); - GraphTraceLen = 256; - ShowGraphWindow(); - RepaintGraphWindow(); - } else { + clearCommandBuffer(); + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0); + PacketResponseNG resp; + while (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 2000)) { + timeout++; + printf("."); + fflush(stdout); + if (timeout > 7) { + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); + return PM3_ETIMEOUT; + } + } + PrintAndLogEx(NORMAL, "\n"); - PrintAndLogEx(FAILED, "\nNot showing LF tuning graph since all values is zero.\n\n"); - } - return 0; + uint32_t v_lf125 = resp.oldarg[0]; + uint32_t v_lf134 = resp.oldarg[0] >> 32; + + uint32_t v_hf = resp.oldarg[1]; + uint32_t peakf = resp.oldarg[2]; + uint32_t peakv = resp.oldarg[2] >> 32; + + if (v_lf125 > NON_VOLTAGE) + PrintAndLogEx(SUCCESS, "LF antenna: %5.2f V - 125.00 kHz", (v_lf125 * ANTENNA_ERROR) / 1000.0); + if (v_lf134 > NON_VOLTAGE) + PrintAndLogEx(SUCCESS, "LF antenna: %5.2f V - 134.00 kHz", (v_lf134 * ANTENNA_ERROR) / 1000.0); + if (peakv > NON_VOLTAGE && peakf > 0) + PrintAndLogEx(SUCCESS, "LF optimal: %5.2f V - %6.2f kHz", (peakv * ANTENNA_ERROR) / 1000.0, 12000.0 / (peakf + 1)); + + char judgement[20]; + memset(judgement, 0, sizeof(judgement)); + // LF evaluation + if (peakv < LF_UNUSABLE_V) + sprintf(judgement, _RED_("UNUSABLE")); + else if (peakv < LF_MARGINAL_V) + sprintf(judgement, _YELLOW_("MARGINAL")); + else + sprintf(judgement, _GREEN_("OK")); + + PrintAndLogEx(NORMAL, "%sLF antenna is %s \n" + , (peakv < LF_UNUSABLE_V) ? _CYAN_("[!]") : _GREEN_("[+]") + , judgement + ); + + // HF evaluation + if (v_hf > NON_VOLTAGE) + PrintAndLogEx(SUCCESS, "HF antenna: %5.2f V - 13.56 MHz", (v_hf * ANTENNA_ERROR) / 1000.0); + + memset(judgement, 0, sizeof(judgement)); + + if (v_hf < HF_UNUSABLE_V) + sprintf(judgement, _RED_("UNUSABLE")); + else if (v_hf < HF_MARGINAL_V) + sprintf(judgement, _YELLOW_("MARGINAL")); + else + sprintf(judgement, _GREEN_("OK")); + + PrintAndLogEx(NORMAL, "%sHF antenna is %s" + , (v_hf < HF_UNUSABLE_V) ? _CYAN_("[!]") : _GREEN_("[+]") + , judgement + ); + + // graph LF measurements + // even here, these values has 3% error. + uint16_t test1 = 0; + for (int i = 0; i < 256; i++) { + GraphBuffer[i] = resp.data.asBytes[i] - 128; + test1 += resp.data.asBytes[i]; + } + + if (test1 > 0) { + PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor 89 is 134khz, 95 is 125khz.\n\n"); + GraphTraceLen = 256; + ShowGraphWindow(); + RepaintGraphWindow(); + } else { + + PrintAndLogEx(FAILED, "\nNot showing LF tuning graph since all values is zero.\n\n"); + } + + return PM3_SUCCESS; } -int CmdLoad(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; +static int CmdLoad(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, "r"); - if (!f) { - PrintAndLogEx(WARNING, "couldn't open '%s'", filename); - return 0; - } + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); - GraphTraceLen = 0; - char line[80]; - while (fgets(line, sizeof (line), f)) { - GraphBuffer[GraphTraceLen] = atoi(line); - GraphTraceLen++; - } - if (f) - fclose(f); + FILE *f = fopen(filename, "r"); + if (!f) { + PrintAndLogEx(WARNING, "couldn't open '%s'", filename); + return PM3_EFILE; + } - PrintAndLogEx(SUCCESS, "loaded %d samples", GraphTraceLen); - setClockGrid(0,0); - DemodBufferLen = 0; - RepaintGraphWindow(); - -//ICEMAN todo - // set signal properties low/high/mean/amplitude and isnoice detection - justNoise(GraphBuffer, GraphTraceLen); - return 0; + GraphTraceLen = 0; + char line[80]; + while (fgets(line, sizeof(line), f)) { + GraphBuffer[GraphTraceLen] = atoi(line); + GraphTraceLen++; + + if (GraphTraceLen >= MAX_GRAPH_TRACE_LEN) + break; + } + + fclose(f); + + PrintAndLogEx(SUCCESS, "loaded %d samples", GraphTraceLen); + + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + + removeSignalOffset(bits, size); + setGraphBuf(bits, size); + computeSignalProperties(bits, size); + + setClockGrid(0, 0); + DemodBufferLen = 0; + RepaintGraphWindow(); + return PM3_SUCCESS; } // trim graph from the end int CmdLtrim(const char *Cmd) { - // sanitycheck - if (GraphTraceLen <= 0) return 1; - int ds = atoi(Cmd); - for (int i = ds; i < GraphTraceLen; ++i) - GraphBuffer[i-ds] = GraphBuffer[i]; + uint32_t ds = strtoul(Cmd, NULL, 10); - GraphTraceLen -= ds; - RepaintGraphWindow(); - return 0; + // sanitycheck + if (GraphTraceLen <= ds) return PM3_ESOFT; + + for (uint32_t i = ds; i < GraphTraceLen; ++i) + GraphBuffer[i - ds] = GraphBuffer[i]; + + GraphTraceLen -= ds; + RepaintGraphWindow(); + return PM3_SUCCESS; } // trim graph from the beginning -int CmdRtrim(const char *Cmd) { - - int ds = atoi(Cmd); +static int CmdRtrim(const char *Cmd) { - // sanitycheck - if (GraphTraceLen <= ds) return 1; + uint32_t ds = strtoul(Cmd, NULL, 10); - GraphTraceLen = ds; - RepaintGraphWindow(); - return 0; + // sanitycheck + if (GraphTraceLen <= ds) return PM3_ESOFT; + + GraphTraceLen = ds; + RepaintGraphWindow(); + return PM3_SUCCESS; } // trim graph (middle) piece -int CmdMtrim(const char *Cmd) { - int start = 0, stop = 0; - sscanf(Cmd, "%i %i", &start, &stop); +static int CmdMtrim(const char *Cmd) { + uint32_t start = 0, stop = 0; + sscanf(Cmd, "%u %u", &start, &stop); - if (start > GraphTraceLen || stop > GraphTraceLen || start > stop) return 1; - - // leave start position sample - start++; + if (start > GraphTraceLen || stop > GraphTraceLen || start > stop) return PM3_ESOFT; - GraphTraceLen = stop - start; - for (int i = 0; i < GraphTraceLen; i++) - GraphBuffer[i] = GraphBuffer[start+i]; + // leave start position sample + start++; - return 0; + GraphTraceLen = stop - start; + for (uint32_t i = 0; i < GraphTraceLen; i++) + GraphBuffer[i] = GraphBuffer[start + i]; + + return PM3_SUCCESS; } int CmdNorm(const char *Cmd) { - int i; - int max = INT_MIN, min = INT_MAX; + (void)Cmd; // Cmd is not used so far + int max = INT_MIN, min = INT_MAX; - // Find local min, max - for (i = 10; i < GraphTraceLen; ++i) { - if (GraphBuffer[i] > max) max = GraphBuffer[i]; - if (GraphBuffer[i] < min) min = GraphBuffer[i]; - } + // Find local min, max + for (uint32_t 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(); - -//ICEMAN todo - // set signal properties low/high/mean/amplitude and isnoice detection - justNoise(GraphBuffer, GraphTraceLen); - return 0; + if (max != min) { + for (uint32_t 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 + } + } + + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + // set signal properties low/high/mean/amplitude and is_noise detection + computeSignalProperties(bits, size); + + RepaintGraphWindow(); + return PM3_SUCCESS; } int CmdPlot(const char *Cmd) { - ShowGraphWindow(); - return 0; + (void)Cmd; // Cmd is not used so far + ShowGraphWindow(); + return PM3_SUCCESS; } -int CmdSave(const char *Cmd) { +static int CmdSave(const char *Cmd) { - int len = 0; - char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + char filename[FILE_PATH_SIZE] = {0x00}; - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - FILE *f = fopen(filename, "w"); - if(!f) { - PrintAndLogEx(WARNING, "couldn't open '%s'", filename); - return 0; - } + len = strlen(Cmd); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd, len); - for (int i = 0; i < GraphTraceLen; i++) - fprintf(f, "%d\n", GraphBuffer[i]); + FILE *f = fopen(filename, "w"); + if (!f) { + PrintAndLogEx(WARNING, "couldn't open '%s'", filename); + return PM3_EFILE; + } - if (f) - fclose(f); + for (uint32_t i = 0; i < GraphTraceLen; i++) + fprintf(f, "%d\n", GraphBuffer[i]); - PrintAndLogEx(SUCCESS, "saved to '%s'", Cmd); - return 0; + fclose(f); + + PrintAndLogEx(SUCCESS, "saved to " _YELLOW_("'%s'"), Cmd); + return PM3_SUCCESS; } -int CmdScale(const char *Cmd) { - CursorScaleFactor = atoi(Cmd); - if (CursorScaleFactor == 0) { - PrintAndLogEx(FAILED, "bad, can't have zero scale"); - CursorScaleFactor = 1; - } - RepaintGraphWindow(); - return 0; +static int CmdScale(const char *Cmd) { + CursorScaleFactor = atoi(Cmd); + if (CursorScaleFactor == 0) { + PrintAndLogEx(FAILED, "bad, can't have zero scale"); + CursorScaleFactor = 1; + } + RepaintGraphWindow(); + return PM3_SUCCESS; } -int directionalThreshold(const int* in, int *out, size_t len, int8_t up, int8_t down) { +int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down) { - int lastValue = in[0]; - - // Will be changed at the end, but init 0 as we adjust to last samples - // value if no threshold kicks in. - out[0] = 0; + int lastValue = in[0]; - for (size_t 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]; - } - } - - // Align with first edited sample. - out[0] = out[1]; - return 0; + // Will be changed at the end, but init 0 as we adjust to last samples + // value if no threshold kicks in. + out[0] = 0; + + for (size_t 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]; + } + } + + // Align with first edited sample. + out[0] = out[1]; + return PM3_SUCCESS; } -int CmdDirectionalThreshold(const char *Cmd) { - int8_t up = param_get8(Cmd, 0); - int8_t down = param_get8(Cmd, 1); +static int CmdDirectionalThreshold(const char *Cmd) { + int8_t up = param_get8(Cmd, 0); + int8_t down = param_get8(Cmd, 1); - PrintAndLogEx(INFO, "Applying Up Threshold: %d, Down Threshold: %d\n", up, down); + PrintAndLogEx(INFO, "Applying Up Threshold: %d, Down Threshold: %d\n", up, down); - directionalThreshold(GraphBuffer, GraphBuffer,GraphTraceLen, up, down); - RepaintGraphWindow(); - return 0; + directionalThreshold(GraphBuffer, GraphBuffer, GraphTraceLen, up, down); + + // set signal properties low/high/mean/amplitude and isnoice detection + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + // set signal properties low/high/mean/amplitude and is_noice detection + computeSignalProperties(bits, size); + + RepaintGraphWindow(); + return PM3_SUCCESS; } -int CmdZerocrossings(const char *Cmd) { - // Zero-crossings aren't meaningful unless the signal is zero-mean. - CmdHpf(""); +static int CmdZerocrossings(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + // Zero-crossings aren't meaningful unless the signal is zero-mean. + CmdHpf(""); - int sign = 1, zc = 0, lastZc = 0; + int sign = 1, zc = 0, 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 (uint32_t 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; + } + } + } - //ICEMAN todo - // set signal properties low/high/mean/amplitude and isnoice detection - justNoise(GraphBuffer, GraphTraceLen); - - RepaintGraphWindow(); - return 0; + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + // set signal properties low/high/mean/amplitude and is_noise detection + computeSignalProperties(bits, size); + + RepaintGraphWindow(); + return PM3_SUCCESS; } /** @@ -1757,300 +1860,304 @@ int CmdZerocrossings(const char *Cmd) { * @param Cmd * @return */ -int Cmdbin2hex(const char *Cmd) { - int bg = 0, en = 0; - if (param_getptr(Cmd, &bg, &en, 0)) - return usage_data_bin2hex(); +static int Cmdbin2hex(const char *Cmd) { + 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 }; + //Number of digits supplied as argument + size_t length = en - bg + 1; + size_t bytelen = (length + 7) / 8; + uint8_t *arr = (uint8_t *) calloc(bytelen, sizeof(uint8_t)); + 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 - PrintAndLogEx(NORMAL, "Ignoring '%c'", c); - } + for (; bg <= en; bg++) { + char c = Cmd[bg]; + if (c == '1') + pushBit(&bout, 1); + else if (c == '0') + pushBit(&bout, 0); + else + PrintAndLogEx(NORMAL, "Ignoring '%c'", c); + } - if (bout.numbits % 8 != 0) - PrintAndLogEx(NORMAL, "[padded with %d zeroes]", 8 - (bout.numbits % 8)); + if (bout.numbits % 8 != 0) + PrintAndLogEx(NORMAL, "[padded with %d zeroes]", 8 - (bout.numbits % 8)); - PrintAndLogEx(NORMAL, "%s", sprint_hex(arr, bytelen)); - free(arr); - return 0; + PrintAndLogEx(NORMAL, "%s", sprint_hex(arr, bytelen)); + free(arr); + return PM3_SUCCESS; } -int Cmdhex2bin(const char *Cmd) { - int bg = 0, en = 0; - if (param_getptr(Cmd, &bg, &en, 0)) return usage_data_hex2bin(); +static 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; + 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) - PrintAndLogEx(NORMAL, "%d",(x >> (3 - i)) & 1); - } - PrintAndLogEx(NORMAL, "\n"); - return 0; + //Uses printf instead of PrintAndLog since the latter adds linebreaks to each printout + for (int i = 0 ; i < 4 ; ++i) + printf("%d", (x >> (3 - i)) & 1); + } + PrintAndLogEx(NORMAL, "\n"); + return PM3_SUCCESS; } - /* // 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 +/* // 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 +}; +*/ +static 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; - // 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; - } + // 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 - // 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; - } - } + // 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; + } - int k; - // add last -1 modifiers - for (k = 0; k < Right_Modifier; k++) { - LowTone[ ( (i-1) * LowToneFC) + Left_Modifier + j + k] = -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; + } + } - // 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; + int k; + // add last -1 modifiers + for (k = 0; k < Right_Modifier; k++) { + LowTone[((i - 1) * LowToneFC) + Left_Modifier + j + k] = -1; + } - for (i = 0; i < Left_Modifier; i++) { - HighTone[i] = 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; - // 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; - } - } + for (i = 0; i < Left_Modifier; i++) { + HighTone[i] = 1; + } - // add last -1 modifiers - for (k = 0; k < Right_Modifier; k++) { - PrintAndLogEx(NORMAL, "(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++) { - PrintAndLogEx(NORMAL, "Low: %i, High: %i", LowTone[i], HighTone[i]); - } - } + // 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++) { + PrintAndLogEx(NORMAL, "(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++) { + PrintAndLogEx(NORMAL, "Low: %i, High: %i", LowTone[i], HighTone[i]); + } + } } -//old CmdFSKdemod adapted by marshmellow +//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, &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 i, j; - int LowTone[clk]; - int HighTone[clk]; - GetHiLoTone(LowTone, HighTone, clk, LowToneFC, HighToneFC); +static int FSKToNRZ(int *data, size_t *dataLen, uint8_t clk, uint8_t LowToneFC, uint8_t 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, &firstClockEdge); + if (g_debugMode > 1) { + PrintAndLogEx(NORMAL, "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) { + PrintAndLogEx(NORMAL, "DEBUG FSKtoNRZ: no fsk clocks found"); + } + return PM3_ESOFT; + } - // loop through ([all samples] - clk) - for (i = 0; i < *dataLen - clk; ++i) { - int lowSum = 0, highSum = 0; + int LowTone[clk]; + int HighTone[clk]; + GetHiLoTone(LowTone, HighTone, clk, LowToneFC, HighToneFC); - // 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; - } + // loop through ([all samples] - clk) + for (size_t i = 0; i < *dataLen - clk; ++i) { + int lowSum = 0, highSum = 0; - // 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 all samples together starting from this sample for [clk] samples for each tone (multiply tone value with sample data) + for (size_t 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; + } - // 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); - } + // 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 (size_t i = 0; i < *dataLen - clk - LowToneFC; ++i) { + int lowTot = 0, highTot = 0; - // 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; + // sum a field clock width of abs( [average sample values per clk] * 100) for each tone + for (size_t j = 0; j < LowToneFC; ++j) { //10 for fsk2 + lowTot += (data[i + j] & 0xffff); + } + for (size_t 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 PM3_SUCCESS; } -int CmdFSKToNRZ(const char *Cmd) { - // take clk, fc_low, fc_high - // blank = auto; - bool errors = false; - char cmdp = 0; - int clk = 0, fc_low = 10, fc_high = 8; - while (param_getchar(Cmd, cmdp) != 0x00) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_data_fsktonrz(); - case 'c': - clk = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'f': - fc_high = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'l': - fc_low = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - if(errors) break; - } - //Validations - if (errors) return usage_data_fsktonrz(); +static int CmdFSKToNRZ(const char *Cmd) { + // take clk, fc_low, fc_high + // blank = auto; + bool errors = false; + char cmdp = 0; + int clk = 0, fc_low = 10, fc_high = 8; + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_data_fsktonrz(); + case 'c': + clk = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'f': + fc_high = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'l': + fc_low = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "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; + setClockGrid(0, 0); + DemodBufferLen = 0; + int ans = FSKToNRZ(GraphBuffer, &GraphTraceLen, clk, fc_low, fc_high); + CmdNorm(""); + RepaintGraphWindow(); + return ans; } -int CmdDataIIR(const char *Cmd){ - uint8_t k = param_get8(Cmd, 0); - //iceIIR_Butterworth(GraphBuffer, GraphTraceLen); - iceSimple_Filter(GraphBuffer, GraphTraceLen, k); - RepaintGraphWindow(); - return 0; +static int CmdDataIIR(const char *Cmd) { + uint8_t k = param_get8(Cmd, 0); + //iceIIR_Butterworth(GraphBuffer, GraphTraceLen); + iceSimple_Filter(GraphBuffer, GraphTraceLen, k); + + uint8_t bits[GraphTraceLen]; + size_t size = getFromGraphBuf(bits); + // set signal properties low/high/mean/amplitude and is_noise detection + computeSignalProperties(bits, size); + RepaintGraphWindow(); + return PM3_SUCCESS; } 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, " -- Converts binary to hexadecimal"}, - {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, - {"buffclear", CmdBuffClear, 1, "Clears bigbuff on deviceside and graph window"}, - {"dec", CmdDec, 1, "Decimate samples"}, - {"detectclock", CmdDetectClockRate, 1, "[] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"}, - {"fsktonrz", CmdFSKToNRZ, 1, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"}, + {"autocorr", CmdAutoCorr, AlwaysAvailable, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"}, + {"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"}, + {"bin2hex", Cmdbin2hex, AlwaysAvailable, " -- Converts binary to hexadecimal"}, + {"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"}, + {"buffclear", CmdBuffClear, AlwaysAvailable, "Clears bigbuff on deviceside and graph window"}, + {"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"}, + {"dec", CmdDec, AlwaysAvailable, "Decimate samples"}, + {"detectclock", CmdDetectClockRate, AlwaysAvailable, "[] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"}, + {"fsktonrz", CmdFSKToNRZ, AlwaysAvailable, "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, " -- 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"}, - {"iir", CmdDataIIR, 0, "apply IIR buttersworth filter on plotdata"}, - {NULL, NULL, 0, NULL} + {"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, + {"grid", CmdGrid, AlwaysAvailable, " -- overlay grid on graph window, use zero value to turn off either"}, + {"hexsamples", CmdHexsamples, IfPm3Present, " [] -- Dump big buffer as hex bytes"}, + {"hex2bin", Cmdhex2bin, AlwaysAvailable, " -- Converts hexadecimal to binary"}, + {"hide", CmdHide, AlwaysAvailable, "Hide graph window"}, + {"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"}, + {"load", CmdLoad, AlwaysAvailable, " -- Load trace (to graph window"}, + {"ltrim", CmdLtrim, AlwaysAvailable, " -- Trim samples from left of trace"}, + {"rtrim", CmdRtrim, AlwaysAvailable, " -- Trim samples from right of trace"}, + {"mtrim", CmdMtrim, AlwaysAvailable, " -- Trim out samples from the specified start to the specified stop"}, + {"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"}, + {"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"}, + {"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"}, + {"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] [l] -- print the data in the DemodBuffer - 'x' for hex output"}, + {"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, + {"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, + {"save", CmdSave, AlwaysAvailable, " -- Save trace (from graph window)"}, + {"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"}, + {"scale", CmdScale, AlwaysAvailable, " -- Set cursor display scale"}, + {"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"}, + {"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, " -- Shift 0 for Graphed wave + or - shift value"}, + {"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, + {"tune", CmdTuneSamples, IfPm3Present, "Get hw tune samples for graph window"}, + {"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"}, + {"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"}, + {"iir", CmdDataIIR, IfPm3Present, "apply IIR buttersworth filter on plotdata"}, + {NULL, NULL, NULL, NULL} }; -int CmdData(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +int CmdData(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } + diff --git a/client/cmddata.h b/client/cmddata.h index dbd735747..583af4dd1 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -22,28 +22,22 @@ #include // for CmdNorm INT_MIN && INT_MAX #include "util.h" #include "cmdmain.h" -#include "proxmark3.h" // sendcommand +#include "proxmark3.h"// sendcommand #include "ui.h" // for show graph controls #include "graph.h" // for graph data -#include "usb_cmd.h" // already included in cmdmain.h and proxmark3.h +#include "comms.h" #include "lfdemod.h" // for demod code #include "crc.h" // for pyramid checksum maxim #include "crc16.h" // for FDXB demod checksum #include "loclass/cipherutils.h" // for decimating samples in getsamples #include "cmdlfem4x.h" // askem410xdecode -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); +// Still quite work to do here to provide proper functions for internal usage... +/* 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 CmdAskEdgeDetect(const char *Cmd); int CmdAutoCorr(const char *Cmd); int CmdBiphaseDecodeRaw(const char *Cmd); @@ -52,41 +46,49 @@ 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 CmdPSKIdteck(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 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 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 CmdDataIIR(const char *Cmd); +*/ +int CmdPrintDemodBuff(const char *Cmd); // used by cmd lf keri, lf nexwatch +int CmdPSK1rawDemod(const char *Cmd); // used by cmd lf +int CmdGetBitStream(const char *Cmd); // used by cmd lf +int CmdGrid(const char *Cmd); // used by cmd lf cotag +int CmdHpf(const char *Cmd); // used by cmd lf data (!) +int CmdLtrim(const char *Cmd); // used by cmd lf em4x, lf t55xx +int CmdNorm(const char *Cmd); // used by cmd lf data (!) +int CmdPlot(const char *Cmd); // used by cmd lf cotag +int CmdTuneSamples(const char *Cmd); // used by cmd lf hw +int ASKbiphaseDemod(const char *Cmd, bool verbose); // used by cmd lf em4x, lf fdx, lf guard, lf jablotron, lf nedap, lf t55xx +int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType); // used by cmd lf em4x, lf t55xx, lf viking +int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, bool *stCheck); // used by cmd lf, lf em4x, lf noralsy, le presco, lf securekey, lf t55xx, lf visa2k +int FSKrawDemod(const char *Cmd, bool verbose); // used by cmd lf, lf em4x, lf t55xx +int PSKDemod(const char *Cmd, bool verbose); // used by cmd lf em4x, lf indala, lf keri, lf nexwatch, lf t55xx +int NRZrawDemod(const char *Cmd, bool verbose); // used by cmd lf pac, lf t55xx + + +void printDemodBuff(void); +void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx); +bool getDemodBuff(uint8_t *buff, size_t *size); +void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore +int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveGrph, bool verbose); +int getSamples(uint32_t n, bool silent); +void setClockGrid(uint32_t clk, int offset); +int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down); +int AskEdgeDetect(const int *in, int *out, int len, int threshold); +int demodIdteck(void); #define MAX_DEMOD_BUF_LEN (1024*128) #define BIGBUF_SIZE 40000 diff --git a/client/cmdflashmem.c b/client/cmdflashmem.c index 2b86bdcfc..dafda3ae6 100644 --- a/client/cmdflashmem.c +++ b/client/cmdflashmem.c @@ -9,520 +9,624 @@ //----------------------------------------------------------------------------- #include "cmdflashmem.h" -#include "rsa.h" -#include "sha1.h" +#include "mbedtls/rsa.h" +#include "mbedtls/sha1.h" +#include "mbedtls/base64.h" + +#define MCK 48000000 +#define FLASH_MINFAST 24000000 //33000000 +#define FLASH_BAUD MCK/2 +#define FLASH_FASTBAUD MCK +#define FLASH_MINBAUD FLASH_FASTBAUD + +#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST) static int CmdHelp(const char *Cmd); -int usage_flashmem_read(void){ - PrintAndLogEx(NORMAL, "Read flash memory on device"); - PrintAndLogEx(NORMAL, "Usage: mem read o l "); - PrintAndLogEx(NORMAL, " o : offset in memory"); - PrintAndLogEx(NORMAL, " l : length"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem read o 0 l 32"); // read 32 bytes starting at offset 0 - PrintAndLogEx(NORMAL, " mem read o 1024 l 10"); // read 10 bytes starting at offset 1024 - return 0; -} -int usage_flashmem_load(void){ - PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); - PrintAndLogEx(NORMAL, "Usage: mem load o f "); - PrintAndLogEx(NORMAL, " o : offset in memory"); - PrintAndLogEx(NORMAL, " f : file name"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 - PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024 - return 0; -} -int usage_flashmem_save(void){ - PrintAndLogEx(NORMAL, "Saves flash memory on device into the file"); - PrintAndLogEx(NORMAL, " Usage: mem save o l f "); - PrintAndLogEx(NORMAL, " o : offset in memory"); - PrintAndLogEx(NORMAL, " l : length"); - PrintAndLogEx(NORMAL, " f : file name"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem save f myfile"); // download whole flashmem to file myfile - PrintAndLogEx(NORMAL, " mem save f myfile l 4096"); // download 4096 bytes from default offset 0 to file myfile - PrintAndLogEx(NORMAL, " mem save f myfile o 1024 l 4096"); // downlowd 4096 bytes from offset 1024 to file myfile - return 0; -} -int usage_flashmem_wipe(void){ - - PrintAndLogEx(WARNING, "[OBS] use with caution."); - PrintAndLogEx(NORMAL, "Wipe flash memory on device, which fills memory with 0xFF\n"); - PrintAndLogEx(NORMAL, " Usage: mem wipe p "); - PrintAndLogEx(NORMAL, " p : 0,1,2 page memory"); -// PrintAndLogEx(NORMAL, " i : inital total wipe"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem wipe "); // wipe page 0,1,2 - PrintAndLogEx(NORMAL, " mem wipe p 0"); // wipes first page. - return 0; -} -int usage_flashmem_info(void){ - PrintAndLogEx(NORMAL, "Collect signature and verify it from flash memory\n"); - PrintAndLogEx(NORMAL, " Usage: mem info [h|s|w]"); - PrintAndLogEx(NORMAL, " s : create a signature"); - PrintAndLogEx(NORMAL, " w : write signature to flash memory"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem info"); - PrintAndLogEx(NORMAL, " mem info s"); - return 0; +static int usage_flashmem_spibaud(void) { + PrintAndLogEx(NORMAL, "Usage: mem spibaud [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " SPI baudrate in MHz [24|48]"); + PrintAndLogEx(NORMAL, " "); + PrintAndLogEx(NORMAL, " If >= 24Mhz, FASTREADS instead of READS instruction will be used."); + PrintAndLogEx(NORMAL, " Reading Flash ID will virtually always fail under 48Mhz setting"); + PrintAndLogEx(NORMAL, " Unless you know what you are doing, please stay at 24Mhz"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem spibaud 48"); + return PM3_SUCCESS; } -int CmdFlashMemRead(const char *Cmd) { - - uint8_t cmdp = 0; - bool errors = false; - uint32_t start_index = 0, len = 0; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'o': - start_index = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'l': - len = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'h': - return usage_flashmem_read(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0 ) return usage_flashmem_read(); - - if (start_index + len > FLASH_MEM_MAX_SIZE) { - PrintAndLogDevice(WARNING, "error, start_index + length is larger than available memory"); - return 1; - } - - UsbCommand c = {CMD_READ_FLASH_MEM, {start_index, len, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; +static int usage_flashmem_read(void) { + PrintAndLogEx(NORMAL, "Read flash memory on device"); + PrintAndLogEx(NORMAL, "Usage: mem read o l "); + PrintAndLogEx(NORMAL, " o : offset in memory"); + PrintAndLogEx(NORMAL, " l : length"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem read o 0 l 32"); // read 32 bytes starting at offset 0 + PrintAndLogEx(NORMAL, " mem read o 1024 l 10"); // read 10 bytes starting at offset 1024 + return PM3_SUCCESS; } -int CmdFlashMemLoad(const char *Cmd){ - - FILE *f; - char filename[FILE_PATH_SIZE] = {0}; - uint8_t cmdp = 0; - bool errors = false; - uint32_t start_index = 0; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'o': - start_index = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'f': - //File handling and reading - if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - case 'h': - return usage_flashmem_load(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0 ) return usage_flashmem_load(); - - // load file - f = fopen(filename, "rb"); - if ( !f ){ - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); - return 1; - } - - // get filesize in order to malloc memory - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - - if (fsize < 0) { - PrintAndLogDevice(WARNING, "error, when getting filesize"); - fclose(f); - return 1; - } - - if (fsize > FLASH_MEM_MAX_SIZE) { - PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); - fclose(f); - return 1; - } - - uint8_t *dump = calloc(fsize, sizeof(uint8_t)); - if (!dump) { - PrintAndLogDevice(WARNING, "error, cannot allocate memory "); - fclose(f); - return 1; - } - - size_t bytes_read = fread(dump, 1, fsize, f); - if (f) - fclose(f); - - //Send to device - uint32_t bytes_sent = 0; - uint32_t bytes_remaining = bytes_read; - - while (bytes_remaining > 0){ - uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); - - UsbCommand c = {CMD_WRITE_FLASH_MEM, {start_index + bytes_sent, bytes_in_packet, 0}}; - - memcpy(c.d.asBytes, dump + bytes_sent, bytes_in_packet); - clearCommandBuffer(); - SendCommand(&c); - - bytes_remaining -= bytes_in_packet; - bytes_sent += bytes_in_packet; - - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - free(dump); - return 1; - } - - uint8_t isok = resp.arg[0] & 0xFF; - if (!isok) - PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); - - } - free(dump); - - PrintAndLogEx(SUCCESS, "Wrote %u bytes to offset %u", bytes_read, start_index); - return 0; +static int usage_flashmem_load(void) { + PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); + PrintAndLogEx(NORMAL, "Usage: mem load [o ] f [m|t|i]"); + PrintAndLogEx(NORMAL, "Warning: mem area to be written must have been wiped first"); + PrintAndLogEx(NORMAL, "(this is already taken care when loading dictionaries)"); + PrintAndLogEx(NORMAL, " o : offset in memory"); + PrintAndLogEx(NORMAL, " f : file name"); + PrintAndLogEx(NORMAL, " m : upload 6 bytes keys (mifare key dictionary)"); + PrintAndLogEx(NORMAL, " i : upload 8 bytes keys (iClass key dictionary)"); + PrintAndLogEx(NORMAL, " t : upload 4 bytes keys (pwd dictionary)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 + PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024 + PrintAndLogEx(NORMAL, " mem load f default_keys m"); + PrintAndLogEx(NORMAL, " mem load f default_pwd t"); + PrintAndLogEx(NORMAL, " mem load f default_iclass_keys i"); + return PM3_SUCCESS; } -int CmdFlashMemSave(const char *Cmd){ - - char filename[FILE_PATH_SIZE] = {0}; - uint8_t cmdp = 0; - bool errors = false; - uint32_t start_index = 0, len = FLASH_MEM_MAX_SIZE; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': return usage_flashmem_save(); - case 'l': - len = param_get32ex(Cmd, cmdp+1, FLASH_MEM_MAX_SIZE, 10); - cmdp += 2; - break; - case 'o': - start_index = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'f': - //File handling - if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0 ) return usage_flashmem_save(); - - uint8_t* dump = calloc(len, sizeof(uint8_t)); - if (!dump) { - PrintAndLogDevice(WARNING, "error, cannot allocate memory "); - return 1; - } - - PrintAndLogEx(NORMAL, "downloading %u bytes from flashmem", len); - if ( !GetFromDevice(FLASH_MEM, dump, len, start_index, NULL, -1, true) ) { - PrintAndLogEx(FAILED, "ERROR; downloading flashmem"); - free(dump); - return 1; - } - - saveFile(filename, "bin", dump, len); - saveFileEML(filename, "eml", dump, len, 16); - free(dump); - return 0; +static int usage_flashmem_save(void) { + PrintAndLogEx(NORMAL, "Saves flash memory on device into the file"); + PrintAndLogEx(NORMAL, " Usage: mem save [o ] [l ] f "); + PrintAndLogEx(NORMAL, " o : offset in memory"); + PrintAndLogEx(NORMAL, " l : length"); + PrintAndLogEx(NORMAL, " f : file name"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem save f myfile"); // download whole flashmem to file myfile + PrintAndLogEx(NORMAL, " mem save f myfile l 4096"); // download 4096 bytes from default offset 0 to file myfile + PrintAndLogEx(NORMAL, " mem save f myfile o 1024 l 4096"); // downlowd 4096 bytes from offset 1024 to file myfile + return PM3_SUCCESS; } -int CmdFlashMemWipe(const char *Cmd){ +static int usage_flashmem_wipe(void) { - uint8_t cmdp = 0; - bool errors = false; - bool initalwipe = false; - uint8_t page = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': return usage_flashmem_wipe(); - case 'p': - page = param_get8ex(Cmd, cmdp+1, 0, 10); - if ( page > 2 ) { - PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); - errors = true; - break; - } - cmdp += 2; - break; - case 'i': - initalwipe = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0 ) return usage_flashmem_wipe(); - - UsbCommand c = {CMD_WIPE_FLASH_MEM, {page, initalwipe, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 8000) ) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; - } - uint8_t isok = resp.arg[0] & 0xFF; - if (isok) - PrintAndLogEx(SUCCESS, "Flash WIPE ok"); - else - PrintAndLogEx(FAILED, "Flash WIPE failed"); + PrintAndLogEx(WARNING, "[OBS] use with caution."); + PrintAndLogEx(NORMAL, "Wipe flash memory on device, which fills memory with 0xFF\n"); - return 0; + PrintAndLogEx(NORMAL, " Usage: mem wipe p "); + PrintAndLogEx(NORMAL, " p : 0,1,2 page memory"); +// PrintAndLogEx(NORMAL, " i : inital total wipe"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem wipe p 0"); // wipes first page. + return PM3_SUCCESS; +} +static int usage_flashmem_info(void) { + PrintAndLogEx(NORMAL, "Collect signature and verify it from flash memory\n"); + PrintAndLogEx(NORMAL, " Usage: mem info"); +// PrintAndLogEx(NORMAL, " s : create a signature"); +// PrintAndLogEx(NORMAL, " w : write signature to flash memory"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " mem info"); +// PrintAndLogEx(NORMAL, " mem info s"); + return PM3_SUCCESS; } -int CmdFlashMemInfo(const char *Cmd){ - uint8_t sha_hash[20] = {0}; - rsa_context rsa; - - uint8_t cmdp = 0; - bool errors = false, shall_write = false, shall_sign = false; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': return usage_flashmem_info(); - case 's': { - shall_sign = true; - cmdp++; - break; - } - case 'w': - shall_write = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors ) return usage_flashmem_info(); - - UsbCommand c = {CMD_INFO_FLASH_MEM, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; - } - - uint8_t isok = resp.arg[0] & 0xFF; - if (!isok) { - PrintAndLogEx(FAILED, "failed"); - return 1; - } +static int CmdFlashMemRead(const char *Cmd) { - // validate signature here - rdv40_validation_t mem; - memcpy(&mem, (rdv40_validation_t *)resp.d.asBytes, sizeof(rdv40_validation_t)); + uint8_t cmdp = 0; + bool errors = false; + uint32_t start_index = 0, len = 0; - // Flash ID hash (sha1) - sha1( mem.flashid, sizeof(mem.flashid), sha_hash ); - - // print header - PrintAndLogEx(INFO, "\n--- Flash memory Information ---------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, "ID | %s", sprint_hex(mem.flashid, sizeof(mem.flashid) )); - PrintAndLogEx(INFO, "SHA1 | %s", sprint_hex(sha_hash, sizeof(sha_hash))); - PrintAndLogEx(INFO, "RSA SIGNATURE |"); - print_hex_break( mem.signature, sizeof(mem.signature), 32); + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'o': + start_index = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'l': + len = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'h': + return usage_flashmem_read(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } -//------------------------------------------------------------------------------- -// Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) -// + //Validations + if (errors || cmdp == 0) { + usage_flashmem_read(); + return PM3_EINVARG; + } + if (start_index + len > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, start_index + length is larger than available memory"); + return PM3_EOVFLOW; + } -// public key modulus N -#define RSA_N "9292758453063D803DD603D5E777D788" \ - "8ED1D5BF35786190FA2F23EBC0848AEA" \ - "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ - "7130B9CED7ACDF54CFC7555AC14EEBAB" \ - "93A89813FBF3C4F8066D2D800F7C38A8" \ - "1AE31942917403FF4946B0A83D3D3E05" \ - "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ - "5E94BB77B07507233A0BC7BAC8F90F79" + clearCommandBuffer(); + SendCommandMIX(CMD_FLASHMEM_READ, start_index, len, 0, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashmemSpiBaudrate(const char *Cmd) { + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') { + return usage_flashmem_spibaud(); + } + + uint32_t baudrate = param_get32ex(Cmd, 0, 0, 10); + baudrate = baudrate * 1000000; + if (baudrate != FLASH_BAUD && baudrate != FLASH_MINBAUD) { + usage_flashmem_spibaud(); + return PM3_EINVARG; + } + SendCommandMIX(CMD_FLASHMEM_SET_SPIBAUDRATE, baudrate, 0, 0, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemLoad(const char *Cmd) { + + uint32_t start_index = 0; + char filename[FILE_PATH_SIZE] = {0}; + bool errors = false; + uint8_t cmdp = 0; + Dictionary_t d = DICTIONARY_NONE; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_flashmem_load(); + case 'f': + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "Filename too long"); + errors = true; + break; + } + cmdp += 2; + break; + case 'o': + start_index = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'm': + d = DICTIONARY_MIFARE; + cmdp++; + break; + case 't': + d = DICTIONARY_T55XX; + cmdp++; + break; + case 'i': + d = DICTIONARY_ICLASS; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0) { + usage_flashmem_load(); + return PM3_EINVARG; + } + size_t datalen = 0; + uint16_t keycount = 0; + int res = 0; + uint8_t *data = calloc(FLASH_MEM_MAX_SIZE, sizeof(uint8_t)); + + switch (d) { + case DICTIONARY_MIFARE: + start_index = DEFAULT_MF_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount); + if (res || !keycount) { + free(data); + return PM3_EFILE; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_T55XX: + start_index = DEFAULT_T55XX_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount); + if (res || !keycount) { + free(data); + return PM3_EFILE; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_ICLASS: + start_index = DEFAULT_ICLASS_KEYS_OFFSET; + res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount); + if (res || !keycount) { + free(data); + return PM3_EFILE; + } + data[0] = (keycount >> 0) & 0xFF; + data[1] = (keycount >> 8) & 0xFF; + datalen += 2; + break; + case DICTIONARY_NONE: + res = loadFile(filename, ".bin", data, FLASH_MEM_MAX_SIZE, &datalen); + //int res = loadFileEML( filename, data, &datalen); + if (res) { + free(data); + return PM3_EFILE; + } + + if (datalen > FLASH_MEM_MAX_SIZE) { + PrintAndLogDevice(WARNING, "error, filesize is larger than available memory"); + free(data); + return PM3_EOVFLOW; + } + break; + } + + uint8_t *newdata = realloc(data, datalen); + if (newdata == NULL) { + free(data); + return PM3_EMALLOC; + } else { + data = newdata; + } + + //Send to device + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = datalen; + + // fast push mode + conn.block_after_ACK = true; + + while (bytes_remaining > 0) { + uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + clearCommandBuffer(); + + SendCommandOLD(CMD_FLASHMEM_WRITE, start_index + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + conn.block_after_ACK = false; + free(data); + return PM3_ETIMEOUT; + } + + uint8_t isok = resp.oldarg[0] & 0xFF; + if (!isok) { + conn.block_after_ACK = false; + PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); + return PM3_EFLASH; + } + } + + conn.block_after_ACK = false; + free(data); + PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")"bytes to offset "_GREEN_("%u"), datalen, start_index); + return PM3_SUCCESS; +} +static int CmdFlashMemSave(const char *Cmd) { + + char filename[FILE_PATH_SIZE] = {0}; + uint8_t cmdp = 0; + bool errors = false; + uint32_t start_index = 0, len = FLASH_MEM_MAX_SIZE; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_flashmem_save(); + case 'l': + len = param_get32ex(Cmd, cmdp + 1, FLASH_MEM_MAX_SIZE, 10); + cmdp += 2; + break; + case 'o': + start_index = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'f': + //File handling + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "Filename too long"); + errors = true; + break; + } + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0) { + usage_flashmem_save(); + return PM3_EINVARG; + } + + uint8_t *dump = calloc(len, sizeof(uint8_t)); + if (!dump) { + PrintAndLogDevice(WARNING, "error, cannot allocate memory "); + return PM3_EMALLOC; + } + + PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")"bytes from flashmem", len); + if (!GetFromDevice(FLASH_MEM, dump, len, start_index, NULL, -1, true)) { + PrintAndLogEx(FAILED, "ERROR; downloading from flashmemory"); + free(dump); + return PM3_EFLASH; + } + + saveFile(filename, ".bin", dump, len); + saveFileEML(filename, dump, len, 16); + free(dump); + return PM3_SUCCESS; +} +static int CmdFlashMemWipe(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + bool initalwipe = false; + uint8_t page = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_flashmem_wipe(); + case 'p': + page = param_get8ex(Cmd, cmdp + 1, 0, 10); + if (page > 2) { + PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); + errors = true; + break; + } + cmdp += 2; + break; + case 'i': + initalwipe = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0) { + usage_flashmem_wipe(); + return PM3_EINVARG; + } + + clearCommandBuffer(); + SendCommandMIX(CMD_FLASHMEM_WIPE, page, initalwipe, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 8000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + uint8_t isok = resp.oldarg[0] & 0xFF; + if (isok) + PrintAndLogEx(SUCCESS, "Flash WIPE ok"); + else { + PrintAndLogEx(FAILED, "Flash WIPE failed"); + return PM3_EFLASH; + } + + return PM3_SUCCESS; +} +static int CmdFlashMemInfo(const char *Cmd) { + + uint8_t sha_hash[20] = {0}; + mbedtls_rsa_context rsa; + + uint8_t cmdp = 0; + bool errors = false, shall_write = false, shall_sign = false; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_flashmem_info(); + case 's': { + shall_sign = true; + cmdp++; + break; + } + case 'w': + shall_write = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) { + usage_flashmem_info(); + return PM3_EINVARG; + } + + clearCommandBuffer(); + SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + uint8_t isok = resp.oldarg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(FAILED, "failed"); + return PM3_EFLASH; + } + + // validate signature here + rdv40_validation_t mem; + memcpy(&mem, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t)); + + // Flash ID hash (sha1) + mbedtls_sha1(mem.flashid, sizeof(mem.flashid), sha_hash); + + // print header + PrintAndLogEx(INFO, "\n--- Flash memory Information ---------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "ID | %s", sprint_hex(mem.flashid, sizeof(mem.flashid))); + PrintAndLogEx(INFO, "SHA1 | %s", sprint_hex(sha_hash, sizeof(sha_hash))); + PrintAndLogEx(INFO, "RSA SIGNATURE |"); + print_hex_break(mem.signature, sizeof(mem.signature), 32); + +//------------------------------------------------------------------------------- +// RRG Public RSA Key +// // public key Exponent E -#define RSA_E "10001" +#define RSA_E "010001" + +// public key modulus N +#define RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" + +//------------------------------------------------------------------------------- +// Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) +// // private key Exponent D #define RSA_D "24BF6185468786FDD303083D25E64EFC" \ - "66CA472BC44D253102F8B4A9D3BFA750" \ - "91386C0077937FE33FA3252D28855837" \ - "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ - "DF79C5CE07EE72C7F123142198164234" \ - "CABB724CF78B8173B9F880FC86322407" \ - "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ - "071513A1E85B5DFA031F21ECAE91A34D" + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" -// prime P +// prime P #define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ - "2C01CAD19EA484A87EA4377637E75500" \ - "FCB2005C5C7DD6EC4AC023CDA285D796" \ - "C3D9E75E1EFC42488BB4F1D13AC30A57" + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" // prime Q #define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ - "E211C2B9E5DB1ED0BF61D0D9899620F4" \ - "910E4168387E3C30AA1E00C339A79508" \ - "8452DD96A9A5EA5D9DCA68DA636032AF" + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" #define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ - "3C94D22288ACD763FD8E5600ED4A702D" \ - "F84198A5F06C2E72236AE490C93F07F8" \ - "3CC559CD27BC2D1CA488811730BB5725" + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" #define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ - "D8AAEA56749EA28623272E4F7D0592AF" \ - "7C1F1313CAC9471B5C523BFE592F517B" \ - "407A1BD76C164B93DA2D32A383E58357" + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" #define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ - "F38D18D2B2F0E2DD275AA977E2BF4411" \ - "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ - "A74206CEC169D74BF5A8C50D6F48EA08" + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + - #define KEY_LEN 128 - rsa_init(&rsa, RSA_PKCS_V15, 0); + mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); - rsa.len = KEY_LEN; + rsa.len = KEY_LEN; - mpi_read_string( &rsa.N , 16, RSA_N ); - mpi_read_string( &rsa.E , 16, RSA_E ); - mpi_read_string( &rsa.D , 16, RSA_D ); - mpi_read_string( &rsa.P , 16, RSA_P ); - mpi_read_string( &rsa.Q , 16, RSA_Q ); - mpi_read_string( &rsa.DP, 16, RSA_DP ); - mpi_read_string( &rsa.DQ, 16, RSA_DQ ); - mpi_read_string( &rsa.QP, 16, RSA_QP ); + mbedtls_mpi_read_string(&rsa.N, 16, RSA_N); + mbedtls_mpi_read_string(&rsa.E, 16, RSA_E); + mbedtls_mpi_read_string(&rsa.D, 16, RSA_D); + mbedtls_mpi_read_string(&rsa.P, 16, RSA_P); + mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q); + mbedtls_mpi_read_string(&rsa.DP, 16, RSA_DP); + mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ); + mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP); - PrintAndLogEx(INFO, "KEY length | %d", KEY_LEN); - - bool is_keyok = ( rsa_check_pubkey( &rsa ) == 0 || rsa_check_privkey( &rsa ) == 0 ); - if (is_keyok) - PrintAndLogEx(SUCCESS, "RSA key validation ok"); - else - PrintAndLogEx(FAILED, "RSA key validation failed"); - - // - uint8_t from_device[KEY_LEN]; - uint8_t sign[KEY_LEN]; + PrintAndLogEx(INFO, "KEY length | %d", KEY_LEN); - // to be verified - memcpy(from_device, mem.signature, KEY_LEN); - - // to be signed (all zeros - memset(sign, 0, KEY_LEN); - - // Signing (private key) - if (shall_sign) { - - int is_signed = rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, sha_hash, sign ); - if (is_signed == 0) - PrintAndLogEx(SUCCESS, "RSA Signing ok"); - else - PrintAndLogEx(FAILED, "RSA Signing failed"); + bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0); + if (is_keyok) + PrintAndLogEx(SUCCESS, "RSA key validation ok"); + else + PrintAndLogEx(FAILED, "RSA key validation failed"); - if (shall_write) { - // save to mem - c = (UsbCommand){CMD_WRITE_FLASH_MEM, {FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0}}; - memcpy(c.d.asBytes, sign, sizeof(sign)); - clearCommandBuffer(); - SendCommand(&c); - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - } else { - - if (!resp.arg[0]) - PrintAndLogEx(FAILED, "Writing signature failed"); - else - PrintAndLogEx(SUCCESS, "Writing signature ok [offset: %u]", FLASH_MEM_SIGNATURE_OFFSET); - - } - } - PrintAndLogEx(INFO, "Signed | "); - print_hex_break( sign, sizeof(sign), 32); - } - - // Verify (public key) - int is_verified = rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, sha_hash, from_device ); - if (is_verified == 0) - PrintAndLogEx(SUCCESS, "RSA Verification ok"); - else - PrintAndLogEx(FAILED, "RSA Verification failed"); + // + uint8_t from_device[KEY_LEN]; + uint8_t sign[KEY_LEN]; - rsa_free(&rsa); - return 0; + // to be verified + memcpy(from_device, mem.signature, KEY_LEN); + + // to be signed (all zeros + memset(sign, 0, KEY_LEN); + + // Signing (private key) + if (shall_sign) { + + int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign); + if (is_signed == 0) + PrintAndLogEx(SUCCESS, "RSA Signing ok"); + else + PrintAndLogEx(FAILED, "RSA Signing failed"); + + if (shall_write) { + // save to mem + clearCommandBuffer(); + SendCommandOLD(CMD_FLASHMEM_WRITE, FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0, sign, sizeof(sign)); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + } else { + + if (!resp.oldarg[0]) + PrintAndLogEx(FAILED, "Writing signature failed"); + else + PrintAndLogEx(SUCCESS, "Writing signature ok [offset: %u]", FLASH_MEM_SIGNATURE_OFFSET); + + } + } + PrintAndLogEx(INFO, "Signed | "); + print_hex_break(sign, sizeof(sign), 32); + } + + // Verify (public key) + int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device); + if (is_verified == 0) + PrintAndLogEx(SUCCESS, "RSA Verification ok"); + else + PrintAndLogEx(FAILED, "RSA Verification failed"); + + mbedtls_rsa_free(&rsa); + return PM3_SUCCESS; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"read", CmdFlashMemRead, 1, "Read Flash memory [rdv40]"}, - {"info", CmdFlashMemInfo, 1, "Flash memory information [rdv40]"}, - {"load", CmdFlashMemLoad, 1, "Load data into flash memory [rdv40]"}, - {"save", CmdFlashMemSave, 1, "Save data from flash memory [rdv40]"}, - {"wipe", CmdFlashMemWipe, 1, "Wipe data from flash memory [rdv40]"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"spibaud", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate [rdv40]"}, + {"read", CmdFlashMemRead, IfPm3Flash, "Read Flash memory [rdv40]"}, + {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information [rdv40]"}, + {"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory [rdv40]"}, + {"save", CmdFlashMemSave, IfPm3Flash, "Save data from flash memory [rdv40]"}, + {"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory [rdv40]"}, + {NULL, NULL, NULL, NULL} }; -int CmdFlashMem(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +int CmdFlashMem(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } diff --git a/client/cmdflashmem.h b/client/cmdflashmem.h index 99b18b4c5..3c37239b7 100644 --- a/client/cmdflashmem.h +++ b/client/cmdflashmem.h @@ -20,15 +20,17 @@ #include "cmdparser.h" #include "common.h" #include "util.h" -#include "util_posix.h" // msclock -#include "loclass/fileutils.h" //saveFile -#include "cmdmain.h" //getfromdevice +#include "util_posix.h" // msclock +#include "loclass/fileutils.h" //saveFile +#include "comms.h" //getfromdevice -extern int CmdFlashMem(const char *Cmd); +typedef enum { + DICTIONARY_NONE = 0, + DICTIONARY_MIFARE, + DICTIONARY_T55XX, + DICTIONARY_ICLASS +} Dictionary_t; -extern int CmdFlashMemRead(const char* cmd); -extern int CmdFlashMemLoad(const char* cmd); -extern int CmdFlashMemSave(const char* cmd); -extern int CmdFlashMemWipe(const char *Cmd); -extern int CmdFlashMemInfo(const char *Cmd); -#endif \ No newline at end of file +int CmdFlashMem(const char *Cmd); + +#endif diff --git a/client/cmdhf.c b/client/cmdhf.c index 594450271..7e42202a9 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -12,128 +12,170 @@ static int CmdHelp(const char *Cmd); -int usage_hf_search(){ - PrintAndLogEx(NORMAL, "Usage: hf search"); - PrintAndLogEx(NORMAL, "Will try to find a HF read out of the unknown tag. Stops when found."); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, ""); - return 0; -} -int usage_hf_snoop(){ - PrintAndLogEx(NORMAL, "Usage: hf snoop "); - PrintAndLogEx(NORMAL, "The high frequence snoop will assign all available memory on device for snooped data"); - PrintAndLogEx(NORMAL, "User the 'data samples' command to download from device, and 'data plot' to look at it"); - PrintAndLogEx(NORMAL, "Press button to quit the snooping."); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " - skip sample pairs"); - PrintAndLogEx(NORMAL, " - skip number of triggers"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf snoop"); - PrintAndLogEx(NORMAL, " hf snoop 1000 0"); - return 0; +static int usage_hf_search() { + PrintAndLogEx(NORMAL, "Usage: hf search"); + PrintAndLogEx(NORMAL, "Will try to find a HF read out of the unknown tag. Stops when found."); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - This help"); + PrintAndLogEx(NORMAL, ""); + return 0; } -int CmdHFSearch(const char *Cmd){ +static int usage_hf_sniff() { + PrintAndLogEx(NORMAL, "The high frequence sniffer will assign all available memory on device for sniffed data"); + PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it"); + PrintAndLogEx(NORMAL, "Press button to quit the sniffing.\n"); + PrintAndLogEx(NORMAL, "Usage: hf sniff "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h - This help"); + PrintAndLogEx(NORMAL, " - skip sample pairs"); + PrintAndLogEx(NORMAL, " - skip number of triggers"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf sniff"); + PrintAndLogEx(NORMAL, " hf sniff 1000 0"); + return 0; +} - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_hf_search(); - - int ans = CmdHF14AInfo("s"); - if (ans > 0) { - PrintAndLogEx(SUCCESS, "\nValid ISO14443-A Tag Found\n"); - return ans; - } - ans = HF15Reader("", false); - if (ans) { - PrintAndLogEx(SUCCESS, "\nValid ISO15693 Tag Found\n"); - return ans; - } - ans = HFLegicReader("", false); - if ( ans == 0) { - PrintAndLogEx(SUCCESS, "\nValid LEGIC Tag Found\n"); - return 1; - } - ans = CmdHFTopazReader("s"); - if (ans == 0) { - PrintAndLogEx(SUCCESS, "\nValid Topaz Tag Found\n"); - return 1; - } - // 14b and iclass is the longest test (put last) - ans = HF14BReader(false); //CmdHF14BReader("s"); - if (ans) { - PrintAndLogEx(SUCCESS, "\nValid ISO14443-B Tag Found\n"); - return ans; - } - ans = HFiClassReader("", false, false); - if (ans) { - PrintAndLogEx(SUCCESS, "\nValid iClass Tag (or PicoPass Tag) Found\n"); - return ans; - } +static int usage_hf_tune() { + PrintAndLogEx(NORMAL, "Usage: hf tune []"); + PrintAndLogEx(NORMAL, "Continuously measure HF antenna tuning."); + PrintAndLogEx(NORMAL, "Press button or keyboard to interrupt."); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " - number of iterations (default: infinite)"); + PrintAndLogEx(NORMAL, ""); + return 0; +} - /* - ans = CmdHFFelicaReader("s"); - if (ans) { - PrintAndLogEx(NORMAL, "\nValid ISO18092 / FeliCa Found\n"); - return ans; - } - */ - - PrintAndLogEx(FAILED, "\nno known/supported 13.56 MHz tags found\n"); - return 0; +int CmdHFSearch(const char *Cmd) { + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_search(); + + PrintAndLogEx(INFO, "Checking for known tags...\n"); + + if (infoHF14A(false, false) > 0) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n"); + return 1; + } + if (readHF15Uid(false) == 1) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n"); + return 1; + } + if (readLegicUid(false) == 0) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") " found\n"); + return 1; + } + if (readTopazUid() == 0) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") " found\n"); + return 1; + } + // 14b and iclass is the longest test (put last) + if (readHF14B(false) == 1) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") " found\n"); + return 1; + } + if (readIclass(false, false) == 1) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") " found\n"); + return 1; + } + + /* + ans = CmdHFFelicaReader("s"); + if (ans) { + PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") " found\n"); + return ans; + } + */ + + PrintAndLogEx(FAILED, "\nno known/supported 13.56 MHz tags found\n"); + return 0; } int CmdHFTune(const char *Cmd) { - PrintAndLogEx(SUCCESS, "Measuring HF antenna, press button to exit"); - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING_HF}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_tune(); + int iter = param_get32ex(Cmd, 0, 0, 10); + + PacketResponseNG resp; + PrintAndLogEx(SUCCESS, "Measuring HF antenna, click button or press a key to exit"); + clearCommandBuffer(); + uint8_t mode[] = {1}; + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); + if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { + PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF initialization, aborting"); + return PM3_ETIMEOUT; + } + mode[0] = 2; + // loop forever (till button pressed) if iter = 0 (default) + for (uint8_t i = 0; iter == 0 || i < iter; i++) { + if (ukbhit()) { // abort by keyboard press + int gc = getchar(); + (void)gc; + break; + } + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); + if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { + PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting"); + return PM3_ETIMEOUT; + } + if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) + break; + uint16_t volt = resp.data.asDwords[0]; + PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint16_t)(volt / 1000)); + } + mode[0] = 3; + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); + if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { + PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting"); + return PM3_ETIMEOUT; + } + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Done."); + return PM3_SUCCESS; } -int CmdHFSnoop(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_hf_snoop(); - - int skippairs = param_get32ex(Cmd, 0, 0, 10); - int skiptriggers = param_get32ex(Cmd, 1, 0, 10); - - UsbCommand c = {CMD_HF_SNIFFER, {skippairs, skiptriggers, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; +int CmdHFSniff(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_sniff(); + + int skippairs = param_get32ex(Cmd, 0, 0, 10); + int skiptriggers = param_get32ex(Cmd, 1, 0, 10); + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_SNIFFER, skippairs, skiptriggers, 0, NULL, 0); + return 0; } static command_t CommandTable[] = { - {"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... }"}, - {"emv", CmdHFEMV, 1, "{ EMV RFIDs... }"}, - {"felica", CmdHFFelica, 1, "{ ISO18092 / Felica RFIDs... }"}, - {"legic", CmdHFLegic, 1, "{ LEGIC RFIDs... }"}, - {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"mfdes", CmdHFMFDes, 1, "{ MIFARE Desfire RFIDs... }"}, - {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"list", CmdTraceList, 0, "List protocol data in trace buffer"}, - {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"}, - {"snoop", CmdHFSnoop, 0, " Generic HF Snoop"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, + {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, + {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, + {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, + {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"}, + {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, + {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, + {"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"}, + {"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"}, + {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, + {"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"}, + {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, + {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, + {"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"}, + {"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"}, + {"search", CmdHFSearch, AlwaysAvailable, "Search for known HF tags [preliminary]"}, + {"sniff", CmdHFSniff, IfPm3Hfsniff, " Generic HF Sniff"}, + {NULL, NULL, NULL, NULL} }; int CmdHF(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } diff --git a/client/cmdhf.h b/client/cmdhf.h index be369b626..4540caf3d 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -18,25 +18,24 @@ #include "graph.h" #include "ui.h" #include "cmdparser.h" -#include "cmdhf14a.h" // ISO14443-A -#include "cmdhf14b.h" // ISO14443-B -#include "cmdhf15.h" // ISO15693 +#include "cmdhf14a.h" // ISO14443-A +#include "cmdhf14b.h" // ISO14443-B +#include "cmdhf15.h" // ISO15693 #include "cmdhfepa.h" -#include "cmdhflegic.h" // LEGIC -#include "cmdhficlass.h" // ICLASS -#include "cmdhfmf.h" // CLASSIC -#include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc -#include "cmdhfmfdes.h" // DESFIRE -#include "cmdhftopaz.h" // TOPAZ -#include "cmdhffelica.h" // ISO18092 / FeliCa -#include "emv/cmdemv.h" // EMV -#include "cmdtrace.h" // trace list +#include "cmdhflegic.h" // LEGIC +#include "cmdhficlass.h" // ICLASS +#include "cmdhfmf.h" // CLASSIC +#include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc +#include "cmdhfmfp.h" // Mifare Plus +#include "cmdhfmfdes.h" // DESFIRE +#include "cmdhftopaz.h" // TOPAZ +#include "cmdhffelica.h" // ISO18092 / FeliCa +#include "cmdhffido.h" // FIDO authenticators +#include "cmdtrace.h" // trace list -extern int CmdHF(const char *Cmd); -extern int CmdHFTune(const char *Cmd); -extern int CmdHFSearch(const char *Cmd); -extern int CmdHFSnoop(const char *Cmd); +int CmdHF(const char *Cmd); +int CmdHFTune(const char *Cmd); +int CmdHFSearch(const char *Cmd); +int CmdHFSniff(const char *Cmd); -extern int usage_hf_search(); -extern int usage_hf_snoop(); #endif diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 617a703e4..018431a28 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch -// 2011, 2017 Merlok +// 2011, 2017 - 2019 Merlok // 2014, Peter Fillmore // 2015, 2016, 2017 Iceman // @@ -12,840 +12,904 @@ //----------------------------------------------------------------------------- #include "cmdhf14a.h" +bool APDUInFramingEnable = true; + static int CmdHelp(const char *Cmd); -static int waitCmd(uint8_t iLen); +static int waitCmd(uint8_t iSelect); static const manufactureName manufactureMapping[] = { - // ID, "Vendor Country" - { 0x01, "Motorola UK" }, - { 0x02, "ST Microelectronics SA France" }, - { 0x03, "Hitachi, Ltd Japan" }, - { 0x04, "NXP Semiconductors Germany" }, - { 0x05, "Infineon Technologies AG Germany" }, - { 0x06, "Cylink USA" }, - { 0x07, "Texas Instrument France" }, - { 0x08, "Fujitsu Limited Japan" }, - { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, - { 0x0A, "NEC Japan" }, - { 0x0B, "Oki Electric Industry Co. Ltd Japan" }, - { 0x0C, "Toshiba Corp. Japan" }, - { 0x0D, "Mitsubishi Electric Corp. Japan" }, - { 0x0E, "Samsung Electronics Co. Ltd Korea" }, - { 0x0F, "Hynix / Hyundai, Korea" }, - { 0x10, "LG-Semiconductors Co. Ltd Korea" }, - { 0x11, "Emosyn-EM Microelectronics USA" }, - { 0x12, "INSIDE Technology France" }, - { 0x13, "ORGA Kartensysteme GmbH Germany" }, - { 0x14, "SHARP Corporation Japan" }, - { 0x15, "ATMEL France" }, - { 0x16, "EM Microelectronic-Marin SA Switzerland" }, - { 0x17, "KSW Microtec GmbH Germany" }, - { 0x18, "ZMD AG Germany" }, - { 0x19, "XICOR, Inc. USA" }, - { 0x1A, "Sony Corporation Japan" }, - { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, - { 0x1C, "Emosyn USA" }, - { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, - { 0x1E, "Magellan Technology Pty Limited Australia" }, - { 0x1F, "Melexis NV BO Switzerland" }, - { 0x20, "Renesas Technology Corp. Japan" }, - { 0x21, "TAGSYS France" }, - { 0x22, "Transcore USA" }, - { 0x23, "Shanghai belling corp., ltd. China" }, - { 0x24, "Masktech Germany Gmbh Germany" }, - { 0x25, "Innovision Research and Technology Plc UK" }, - { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" }, - { 0x27, "Cypak AB Sweden" }, - { 0x28, "Ricoh Japan" }, - { 0x29, "ASK France" }, - { 0x2A, "Unicore Microsystems, LLC Russian Federation" }, - { 0x2B, "Dallas Semiconductor/Maxim USA" }, - { 0x2C, "Impinj, Inc. USA" }, - { 0x2D, "RightPlug Alliance USA" }, - { 0x2E, "Broadcom Corporation USA" }, - { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" }, - { 0x30, "BeeDar Technology Inc. USA" }, - { 0x31, "RFIDsec Denmark" }, - { 0x32, "Schweizer Electronic AG Germany" }, - { 0x33, "AMIC Technology Corp Taiwan" }, - { 0x34, "Mikron JSC Russia" }, - { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" }, - { 0x36, "IDS Microchip AG Switzerland" }, - { 0x37, "Kovio USA" }, - { 0x38, "HMT Microelectronic Ltd Switzerland" }, - { 0x39, "Silicon Craft Technology Thailand" }, - { 0x3A, "Advanced Film Device Inc. Japan" }, - { 0x3B, "Nitecrest Ltd UK" }, - { 0x3C, "Verayo Inc. USA" }, - { 0x3D, "HID Global USA" }, - { 0x3E, "Productivity Engineering Gmbh Germany" }, - { 0x3F, "Austriamicrosystems AG (reserved) Austria" }, - { 0x40, "Gemalto SA France" }, - { 0x41, "Renesas Electronics Corporation Japan" }, - { 0x42, "3Alogics Inc Korea" }, - { 0x43, "Top TroniQ Asia Limited Hong Kong" }, - { 0x44, "Gentag Inc. USA" }, - { 0x56, "Sensible Object. UK" }, - { 0x00, "no tag-info available" } // must be the last entry + // ID, "Vendor Country" + { 0x01, "Motorola UK" }, + { 0x02, "ST Microelectronics SA France" }, + { 0x03, "Hitachi, Ltd Japan" }, + { 0x04, "NXP Semiconductors Germany" }, + { 0x05, "Infineon Technologies AG Germany" }, + { 0x06, "Cylink USA" }, + { 0x07, "Texas Instrument France" }, + { 0x08, "Fujitsu Limited Japan" }, + { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, + { 0x0A, "NEC Japan" }, + { 0x0B, "Oki Electric Industry Co. Ltd Japan" }, + { 0x0C, "Toshiba Corp. Japan" }, + { 0x0D, "Mitsubishi Electric Corp. Japan" }, + { 0x0E, "Samsung Electronics Co. Ltd Korea" }, + { 0x0F, "Hynix / Hyundai, Korea" }, + { 0x10, "LG-Semiconductors Co. Ltd Korea" }, + { 0x11, "Emosyn-EM Microelectronics USA" }, + { 0x12, "INSIDE Technology France" }, + { 0x13, "ORGA Kartensysteme GmbH Germany" }, + { 0x14, "SHARP Corporation Japan" }, + { 0x15, "ATMEL France" }, + { 0x16, "EM Microelectronic-Marin SA Switzerland" }, + { 0x17, "KSW Microtec GmbH Germany" }, + { 0x18, "ZMD AG Germany" }, + { 0x19, "XICOR, Inc. USA" }, + { 0x1A, "Sony Corporation Japan" }, + { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, + { 0x1C, "Emosyn USA" }, + { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, + { 0x1E, "Magellan Technology Pty Limited Australia" }, + { 0x1F, "Melexis NV BO Switzerland" }, + { 0x20, "Renesas Technology Corp. Japan" }, + { 0x21, "TAGSYS France" }, + { 0x22, "Transcore USA" }, + { 0x23, "Shanghai belling corp., ltd. China" }, + { 0x24, "Masktech Germany Gmbh Germany" }, + { 0x25, "Innovision Research and Technology Plc UK" }, + { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" }, + { 0x27, "Cypak AB Sweden" }, + { 0x28, "Ricoh Japan" }, + { 0x29, "ASK France" }, + { 0x2A, "Unicore Microsystems, LLC Russian Federation" }, + { 0x2B, "Dallas Semiconductor/Maxim USA" }, + { 0x2C, "Impinj, Inc. USA" }, + { 0x2D, "RightPlug Alliance USA" }, + { 0x2E, "Broadcom Corporation USA" }, + { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" }, + { 0x30, "BeeDar Technology Inc. USA" }, + { 0x31, "RFIDsec Denmark" }, + { 0x32, "Schweizer Electronic AG Germany" }, + { 0x33, "AMIC Technology Corp Taiwan" }, + { 0x34, "Mikron JSC Russia" }, + { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" }, + { 0x36, "IDS Microchip AG Switzerland" }, + { 0x37, "Kovio USA" }, + { 0x38, "HMT Microelectronic Ltd Switzerland" }, + { 0x39, "Silicon Craft Technology Thailand" }, + { 0x3A, "Advanced Film Device Inc. Japan" }, + { 0x3B, "Nitecrest Ltd UK" }, + { 0x3C, "Verayo Inc. USA" }, + { 0x3D, "HID Global USA" }, + { 0x3E, "Productivity Engineering Gmbh Germany" }, + { 0x3F, "Austriamicrosystems AG (reserved) Austria" }, + { 0x40, "Gemalto SA France" }, + { 0x41, "Renesas Electronics Corporation Japan" }, + { 0x42, "3Alogics Inc Korea" }, + { 0x43, "Top TroniQ Asia Limited Hong Kong" }, + { 0x44, "Gentag Inc. USA" }, + { 0x45, "Invengo Information Technology Co.Ltd China" }, + { 0x46, "Guangzhou Sysur Microelectronics, Inc China" }, + { 0x47, "CEITEC S.A. Brazil" }, + { 0x48, "Shanghai Quanray Electronics Co. Ltd. China" }, + { 0x49, "MediaTek Inc Taiwan" }, + { 0x4A, "Angstrem PJSC Russia" }, + { 0x4B, "Celisic Semiconductor (Hong Kong) Limited China" }, + { 0x4C, "LEGIC Identsystems AG Switzerland" }, + { 0x4D, "Balluff GmbH Germany" }, + { 0x4E, "Oberthur Technologies France" }, + { 0x4F, "Silterra Malaysia Sdn. Bhd. Malaysia" }, + { 0x50, "DELTA Danish Electronics, Light & Acoustics Denmark" }, + { 0x51, "Giesecke & Devrient GmbH Germany" }, + { 0x52, "Shenzhen China Vision Microelectronics Co., Ltd. China" }, + { 0x53, "Shanghai Feiju Microelectronics Co. Ltd. China" }, + { 0x54, "Intel Corporation USA" }, + { 0x55, "Microsensys GmbH Germany" }, + { 0x56, "Sonix Technology Co., Ltd. Taiwan" }, + { 0x57, "Qualcomm Technologies Inc USA" }, + { 0x58, "Realtek Semiconductor Corp Taiwan" }, + { 0x59, "Freevision Technologies Co. Ltd China" }, + { 0x5A, "Giantec Semiconductor Inc. China" }, + { 0x5B, "JSC Angstrem-T Russia" }, + { 0x5C, "STARCHIP France" }, + { 0x5D, "SPIRTECH France" }, + { 0x5E, "GANTNER Electronic GmbH Austria" }, + { 0x5F, "Nordic Semiconductor Norway" }, + { 0x60, "Verisiti Inc USA" }, + { 0x61, "Wearlinks Technology Inc. China" }, + { 0x62, "Userstar Information Systems Co., Ltd Taiwan" }, + { 0x63, "Pragmatic Printing Ltd. UK" }, + { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico – LSI-TEC Brazil" }, + { 0x65, "Tendyron Corporation China" }, + { 0x66, "MUTO Smart Co., Ltd. Korea" }, + { 0x67, "ON Semiconductor USA" }, + { 0x68, "TUBITAK BILGEM Turkey" }, + { 0x69, "Huada Semiconductor Co., Ltd China" }, + { 0x6A, "SEVENEY France" }, + { 0x6B, "ISSM France" }, + { 0x6C, "Wisesec Ltd Israel" }, + { 0x7C, "DB HiTek Co Ltd Korea" }, + { 0x7D, "SATO Vicinity Australia" }, + { 0x7E, "Holtek Taiwan" }, + { 0x00, "no tag-info available" } // must be the last entry }; // get a product description based on the UID -// uid[8] tag uid -// returns description of the best match -char* getTagInfo(uint8_t uid) { +// uid[8] tag uid +// returns description of the best match +const char *getTagInfo(uint8_t uid) { - int i; - int len = sizeof(manufactureMapping) / sizeof(manufactureName); - - for ( i = 0; i < len; ++i ) - if ( uid == manufactureMapping[i].uid) - return manufactureMapping[i].desc; + int i; + int len = sizeof(manufactureMapping) / sizeof(manufactureName); - //No match, return default - return manufactureMapping[len-1].desc; + for (i = 0; i < len; ++i) + if (uid == manufactureMapping[i].uid) + return manufactureMapping[i].desc; + + //No match, return default + return manufactureMapping[len - 1].desc; } -int usage_hf_14a_sim(void) { -// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); - PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n"); - PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t u [x] [e] [v]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " t : 1 = MIFARE Classic 1k"); - PrintAndLogEx(NORMAL, " 2 = MIFARE Ultralight"); - PrintAndLogEx(NORMAL, " 3 = MIFARE Desfire"); - PrintAndLogEx(NORMAL, " 4 = ISO/IEC 14443-4"); - PrintAndLogEx(NORMAL, " 5 = MIFARE Tnp3xxx"); - PrintAndLogEx(NORMAL, " 6 = MIFARE Mini"); - PrintAndLogEx(NORMAL, " 7 = AMIIBO (NTAG 215), pack 0x8080"); - PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); - PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); -// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); - PrintAndLogEx(NORMAL, " u : 4, 7 byte UID"); - PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader"); - PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); - PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344556677"); -// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); - return 0; +// iso14a apdu input frame length +static uint16_t frameLength = 0; +uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; + +static int usage_hf_14a_sim(void) { +// PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); + PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n"); + PrintAndLogEx(NORMAL, "Usage: hf 14a sim [h] t u [x] [e] [v]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " t : 1 = MIFARE Classic 1k"); + PrintAndLogEx(NORMAL, " 2 = MIFARE Ultralight"); + PrintAndLogEx(NORMAL, " 3 = MIFARE Desfire"); + PrintAndLogEx(NORMAL, " 4 = ISO/IEC 14443-4"); + PrintAndLogEx(NORMAL, " 5 = MIFARE Tnp3xxx"); + PrintAndLogEx(NORMAL, " 6 = MIFARE Mini"); + PrintAndLogEx(NORMAL, " 7 = AMIIBO (NTAG 215), pack 0x8080"); + PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k"); + PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro"); +// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID"); + PrintAndLogEx(NORMAL, " u : 4, 7 byte UID"); + PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader"); + PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); + PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x"); + PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344"); + PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344556677"); +// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); + return 0; } -int usage_hf_14a_sniff(void) { - PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); - PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list 14a'"); - PrintAndLogEx(NORMAL, "Usage: hf 14a sniff [c][r]"); - PrintAndLogEx(NORMAL, "c - triggered by first data from card"); - PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf 14a sniff c r"); - return 0; +static int usage_hf_14a_sniff(void) { + PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); + PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list 14a'"); + PrintAndLogEx(NORMAL, "Usage: hf 14a sniff [c][r]"); + PrintAndLogEx(NORMAL, "c - triggered by first data from card"); + PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf 14a sniff c r"); + return 0; } -int usage_hf_14a_raw(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-p] [-a] [-T] [-t] [-b] <0A 0B 0C ... hex>"); - PrintAndLogEx(NORMAL, " -h this help"); - PrintAndLogEx(NORMAL, " -r do not read response"); - PrintAndLogEx(NORMAL, " -c calculate and append CRC"); - PrintAndLogEx(NORMAL, " -p leave the signal field ON after receive"); - PrintAndLogEx(NORMAL, " -a active signal field ON without select"); - PrintAndLogEx(NORMAL, " -s active signal field ON with select"); - PrintAndLogEx(NORMAL, " -b number of bits to send. Useful for send partial byte"); - PrintAndLogEx(NORMAL, " -t timeout in ms"); - PrintAndLogEx(NORMAL, " -T use Topaz protocol to send command"); - PrintAndLogEx(NORMAL, " -3 ISO14443-3 select only (skip RATS)"); - return 0; +static int usage_hf_14a_raw(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14a raw [-h] [-r] [-c] [-p] [-a] [-T] [-t] [-b] <0A 0B 0C ... hex>"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -r do not read response"); + PrintAndLogEx(NORMAL, " -c calculate and append CRC"); + PrintAndLogEx(NORMAL, " -p leave the signal field ON after receive"); + PrintAndLogEx(NORMAL, " -a active signal field ON without select"); + PrintAndLogEx(NORMAL, " -s active signal field ON with select"); + PrintAndLogEx(NORMAL, " -b number of bits to send. Useful for send partial byte"); + PrintAndLogEx(NORMAL, " -t timeout in ms"); + PrintAndLogEx(NORMAL, " -T use Topaz protocol to send command"); + PrintAndLogEx(NORMAL, " -3 ISO14443-3 select only (skip RATS)"); + return 0; } -int usage_hf_14a_reader(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a reader [k|s|x] [3]"); - PrintAndLogEx(NORMAL, " k keep the field active after command executed"); - PrintAndLogEx(NORMAL, " s silent (no messages)"); - PrintAndLogEx(NORMAL, " x just drop the signal field"); - PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); - return 0; +static int usage_hf_14a_reader(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14a reader [k|s|x] [3]"); + PrintAndLogEx(NORMAL, " k keep the field active after command executed"); + PrintAndLogEx(NORMAL, " s silent (no messages)"); + PrintAndLogEx(NORMAL, " x just drop the signal field"); + PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); + return 0; } -int usage_hf_14a_info(void){ - PrintAndLogEx(NORMAL, "This command makes more extensive tests against a ISO14443a tag in order to collect information"); - PrintAndLogEx(NORMAL, "Usage: hf 14a info [h|s]"); - PrintAndLogEx(NORMAL, " s silent (no messages)"); - PrintAndLogEx(NORMAL, " n test for nack bug"); - return 0; -} -int usage_hf_14a_apdu(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a apdu [-s] [-k] [-t] "); - PrintAndLogEx(NORMAL, " -s activate field and select card"); - PrintAndLogEx(NORMAL, " -k leave the signal field ON after receive response"); - PrintAndLogEx(NORMAL, " -t executes TLV decoder if it possible. TODO!!!!"); - return 0; -} -int usage_hf_14a_antifuzz(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14a antifuzz [4|7|10]"); - PrintAndLogEx(NORMAL, " determine which anticollision phase the command will target."); - return 0; +static int usage_hf_14a_info(void) { + PrintAndLogEx(NORMAL, "This command makes more extensive tests against a ISO14443a tag in order to collect information"); + PrintAndLogEx(NORMAL, "Usage: hf 14a info [h|s]"); + PrintAndLogEx(NORMAL, " s silent (no messages)"); + PrintAndLogEx(NORMAL, " n test for nack bug"); + return 0; } -int CmdHF14AList(const char *Cmd) { - //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead"); - CmdTraceList("14a"); - return 0; +static int CmdHF14AList(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead"); + CmdTraceList("14a"); + return 0; } -int CmdHF14AReader(const char *Cmd) { +int Hf14443_4aGetCardData(iso14a_card_select_t *card) { + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT, 0, 0, NULL, 0); - uint32_t cm = ISO14A_CONNECT; - bool disconnectAfter = true, silent = false; - int cmdp = 0; - - while (param_getchar(Cmd, cmdp) != 0x00) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_14a_reader(); - case '3': - cm |= ISO14A_NO_RATS; - break; - case 'k': - disconnectAfter = false; - break; - case 's': - silent = true; - break; - case 'x': - cm &= ~ISO14A_CONNECT; - break; - default: - PrintAndLogEx(WARNING, "Unknown command."); - return 1; - } - cmdp++; - } + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); - if (!disconnectAfter) - cm |= ISO14A_NO_DISCONNECT; - - UsbCommand c = {CMD_READER_ISO_14443a, {cm, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); + memcpy(card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - if (ISO14A_CONNECT & cm) { - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return 1; - } - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - /* - 0: couldn't read - 1: OK, with ATS - 2: OK, no ATS - 3: proprietary Anticollision - */ - uint64_t select_status = resp.arg[0]; - - if (select_status == 0) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return 1; - } + if (select_status == 0) { + PrintAndLogEx(ERR, "E->iso14443a card select failed"); + return 1; + } - if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - DropField(); - return 1; - } + if (select_status == 2) { + PrintAndLogEx(ERR, "E->Card doesn't support iso14443-4 mode"); + return 1; + } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); + if (select_status == 3) { + PrintAndLogEx(NORMAL, "E->Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(NORMAL, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); + return 1; + } - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); - } - - if (!disconnectAfter) { - if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands"); - } - } + PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLogEx(NORMAL, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); + PrintAndLogEx(NORMAL, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); + if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + PrintAndLogEx(NORMAL, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); + return 1; + } - if (disconnectAfter) { - if (!silent) PrintAndLogEx(SUCCESS, "field dropped."); - } - - return 0; + PrintAndLogEx(NORMAL, " ATS: %s", sprint_hex(card->ats, card->ats_len)); + return 0; } -int CmdHF14AInfo(const char *Cmd) { - - if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_hf_14a_info(); - - bool silent = (Cmd[0] == 's' || Cmd[0] == 'S'); - bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N'); - - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return 0; - } - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); +static int CmdHF14AReader(const char *Cmd) { - /* - 0: couldn't read - 1: OK, with ATS - 2: OK, no ATS - 3: proprietary Anticollision - */ - uint64_t select_status = resp.arg[0]; - - if (select_status == 0) { - if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); - return 0; - } + uint32_t cm = ISO14A_CONNECT; + bool disconnectAfter = true, silent = false; + int cmdp = 0; - if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - DropField(); - return select_status; - } + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_14a_reader(); + case '3': + cm |= ISO14A_NO_RATS; + break; + case 'k': + disconnectAfter = false; + break; + case 's': + silent = true; + break; + case 'x': + cm &= ~ISO14A_CONNECT; + break; + default: + PrintAndLogEx(WARNING, "Unknown command."); + return 1; + } + cmdp++; + } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); + if (!disconnectAfter) + cm |= ISO14A_NO_DISCONNECT; - bool isMifareClassic = true; - switch (card.sak) { - case 0x00: - isMifareClassic = false; - - // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) - DropField(); - - uint32_t tagT = GetHF14AMfU_Type(); - if (tagT != UL_ERROR) - ul_print_type(tagT, 0); - else - PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)"); + clearCommandBuffer(); + SendCommandMIX(CMD_READER_ISO_14443a, cm, 0, 0, NULL, 0); - // reconnect for further tests - c.arg[0] = ISO14A_CONNECT | ISO14A_NO_DISCONNECT; - c.arg[1] = 0; - c.arg[2] = 0; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK, &resp); - - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + if (ISO14A_CONNECT & cm) { + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + return 1; + } - select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - - if(select_status == 0) { - DropField(); - return 0; - } - break; - case 0x01: PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance"); break; - case 0x04: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); isMifareClassic = false; break; - case 0x08: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); break; - case 0x09: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k"); break; - case 0x0A: PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)"); break; - case 0x10: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2"); break; - case 0x11: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2"); break; - case 0x18: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); break; - case 0x20: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); isMifareClassic = false; break; - case 0x24: PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1"); isMifareClassic = false; break; - case 0x28: PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1"); break; - case 0x38: PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); break; - case 0x88: PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K"); break; - case 0x98: PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS"); break; - default: ; - } + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - // Double & triple sized UID, can be mapped to a manufacturer. - if ( card.uidlen > 4 ) { - PrintAndLogEx(NORMAL, "MANUFACTURER : %s", getTagInfo(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); - clearCommandBuffer(); - 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 - } + /* + 0: couldn't read + 1: OK, with ATS + 2: OK, no ATS + 3: proprietary Anticollision + */ + uint64_t select_status = resp.oldarg[0]; - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - bool ta1 = 0, tb1 = 0, tc1 = 0; - int pos; + if (select_status == 0) { + if (!silent) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + return 1; + } - if (select_status == 2) { - PrintAndLogEx(NORMAL, "SAK incorrectly claims that card doesn't support RATS"); - } - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]); - if (card.ats[0] != card.ats_len - 2) { - PrintAndLogEx(NORMAL, "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; - - PrintAndLogEx(NORMAL, " - T0 : TA1 is%s present, TB1 is%s present, " - "TC1 is%s present, FSCI is %d (FSC = %ld)", - (ta1 ? "" : " NOT"), - (tb1 ? "" : " NOT"), - (tc1 ? "" : " NOT"), - fsci, - fsci < 5 ? (fsci - 2) * 8 : - fsci < 8 ? (fsci - 3) * 32 : - fsci == 8 ? 256 : - -1 - ); - } - pos = 2; - if (ta1) { - 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 (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; - if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; - PrintAndLogEx(NORMAL, " - TA1 : different divisors are%s supported, " - "DR: [%s], DS: [%s]", - (card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds); - pos++; - } - if (tb1) { - uint32_t sfgi = card.ats[pos] & 0x0F; - uint32_t fwi = card.ats[pos] >> 4; - PrintAndLogEx(NORMAL, " - 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 - ); - pos++; - } - if (tc1) { - PrintAndLogEx(NORMAL, " - TC1 : NAD is%s supported, CID is%s supported", - (card.ats[pos] & 0x01) ? "" : " NOT", - (card.ats[pos] & 0x02) ? "" : " NOT"); - pos++; - } - if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2 ) { - char *tip = ""; - if (card.ats[0] - 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) { - tip = "-> MIFARE Plus S 2K or 4K"; - } - } - PrintAndLogEx(NORMAL, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); - if (card.ats[pos] == 0xC1) { - PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type"); - PrintAndLogEx(NORMAL, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); - switch (card.ats[pos + 2] & 0xf0) { - case 0x10: PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire"); break; - case 0x20: PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus"); break; - } - switch (card.ats[pos + 2] & 0x0f) { - case 0x00: PrintAndLogEx(NORMAL, " x0 -> <1 kByte"); break; - case 0x01: PrintAndLogEx(NORMAL, " x1 -> 1 kByte"); break; - case 0x02: PrintAndLogEx(NORMAL, " x2 -> 2 kByte"); break; - case 0x03: PrintAndLogEx(NORMAL, " x3 -> 4 kByte"); break; - case 0x04: PrintAndLogEx(NORMAL, " x4 -> 8 kByte"); break; - } - switch (card.ats[pos + 3] & 0xf0) { - case 0x00: PrintAndLogEx(NORMAL, " 0x -> Engineering sample"); break; - case 0x20: PrintAndLogEx(NORMAL, " 2x -> Released"); break; - } - switch (card.ats[pos + 3] & 0x0f) { - case 0x00: PrintAndLogEx(NORMAL, " x0 -> Generation 1"); break; - case 0x01: PrintAndLogEx(NORMAL, " x1 -> Generation 2"); break; - case 0x02: PrintAndLogEx(NORMAL, " x2 -> Generation 3"); break; - } - switch (card.ats[pos + 4] & 0x0f) { - case 0x00: PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported"); break; - case 0x01: PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported"); break; - case 0x0E: PrintAndLogEx(NORMAL, " xE -> no VCS command supported"); break; - } - } - } - } else { - PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); - } - - detect_classic_magic(); - - if (isMifareClassic) { - int res = detect_classic_prng(); - if ( res == 1 ) - PrintAndLogEx(SUCCESS, "Prng detection: WEAK"); - else if (res == 0 ) - PrintAndLogEx(SUCCESS, "Prng detection: HARD"); - else - PrintAndLogEx(FAILED, "prng detection: failed"); - - if ( do_nack_test ) - detect_classic_nackbug(silent); - } - - return select_status; + if (select_status == 3) { + PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + DropField(); + return 1; + } + + PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + + if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + } + + if (!disconnectAfter) { + if (!silent) PrintAndLogEx(SUCCESS, "Card is selected. You can now start sending commands"); + } + } + + if (disconnectAfter) { + if (!silent) PrintAndLogEx(SUCCESS, "field dropped."); + } + + return 0; +} + +static int CmdHF14AInfo(const char *Cmd) { + + if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_hf_14a_info(); + + bool verbose = !(Cmd[0] == 's' || Cmd[0] == 'S'); + bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N'); + infoHF14A(verbose, do_nack_test); + return 0; } // Collect ISO14443 Type A UIDs -int CmdHF14ACUIDs(const char *Cmd) { - // requested number of UIDs - int n = atoi(Cmd); - // collect at least 1 (e.g. if no parameter was given) - n = n > 0 ? n : 1; +static int CmdHF14ACUIDs(const char *Cmd) { + // requested number of UIDs + int n = atoi(Cmd); + // collect at least 1 (e.g. if no parameter was given) + n = n > 0 ? n : 1; - uint64_t t1 = msclock(); - PrintAndLogEx(SUCCESS, "collecting %d UIDs", n); + uint64_t t1 = msclock(); + PrintAndLogEx(SUCCESS, "collecting %d UIDs", n); - // repeat n times - for (int i = 0; i < n; i++) { + // repeat n times + for (int i = 0; i < n; i++) { - if (ukbhit()) { - int gc = getchar(); (void)gc; - PrintAndLogEx(NORMAL, "\n[!] aborted via keyboard!\n"); - break; - } - - // execute anticollision procedure - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + if (ukbhit()) { + int gc = getchar(); + (void)gc; + PrintAndLogEx(WARNING, "\n[!] aborted via keyboard!\n"); + break; + } - iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; + // execute anticollision procedure + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); - // check if command failed - if (resp.arg[0] == 0) { - PrintAndLogEx(WARNING, "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]); - } - PrintAndLogEx(NORMAL, "%s", uid_string); - } - } - PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock()-t1)/1000); - return 1; + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t *card = (iso14a_card_select_t *) resp.data.asBytes; + + // check if command failed + if (resp.oldarg[0] == 0) { + PrintAndLogEx(WARNING, "card select failed."); + } else { + char uid_string[20]; + for (uint16_t m = 0; m < card->uidlen; m++) { + sprintf(&uid_string[2 * m], "%02X", card->uid[m]); + } + PrintAndLogEx(NORMAL, "%s", uid_string); + } + } + PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000); + return 1; } - // ## simulate iso14443a tag int CmdHF14ASim(const char *Cmd) { - bool errors = false; - uint8_t flags = 0; - uint8_t tagtype = 1; - uint8_t cmdp = 0; - uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0}; - int uidlen = 0; - bool useUIDfromEML = true; - bool setEmulatorMem = false; - bool verbose = false; - nonces_t data[1]; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_14a_sim(); - case 't': - case 'T': - // Retrieve the tag type - tagtype = param_get8ex(Cmd, cmdp+1, 0, 10); - if (tagtype == 0) - errors = true; - cmdp += 2; - break; - case 'u': - case 'U': - // Retrieve the full 4,7,10 byte long uid - param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); - switch(uidlen) { - //case 20: flags |= FLAG_10B_UID_IN_DATA; break; - case 14: flags |= FLAG_7B_UID_IN_DATA; break; - case 8: flags |= FLAG_4B_UID_IN_DATA; break; - default: errors = true; break; - } - if (!errors) { - PrintAndLogEx(SUCCESS, "Emulating ISO/IEC 14443 type A tag with %d byte UID (%s)", uidlen>>1, sprint_hex(uid, uidlen>>1)); - useUIDfromEML = false; - } - cmdp += 2; - break; - case 'v': - case 'V': - verbose = true; - cmdp++; - break; - case 'x': - case 'X': - flags |= FLAG_NR_AR_ATTACK; - cmdp++; - break; - case 'e': - case 'E': - setEmulatorMem = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_14a_sim(); + int uidlen = 0; + uint8_t flags = 0, tagtype = 1, cmdp = 0; + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + bool useUIDfromEML = true; + bool setEmulatorMem = false; + bool verbose = false; + bool errors = false; - if ( useUIDfromEML ) - flags |= FLAG_UID_IN_EMUL; - - UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,{ tagtype, flags, 0 }}; - memcpy(c.d.asBytes, uid, uidlen>>1); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); - - while( !ukbhit() ){ - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) continue; - if ( !(flags & FLAG_NR_AR_ATTACK) ) break; - if ( (resp.arg[0] & 0xffff) != CMD_SIMULATE_MIFARE_CARD ) break; - - memcpy(data, resp.d.asBytes, sizeof(data) ); - readerAttack(data[0], setEmulatorMem, verbose); - } - showSectorTable(); - return 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_14a_sim(); + case 't': + // Retrieve the tag type + tagtype = param_get8ex(Cmd, cmdp + 1, 0, 10); + if (tagtype == 0) + errors = true; + cmdp += 2; + break; + case 'u': + // Retrieve the full 4,7,10 byte long uid + param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); + uidlen >>= 1; + switch (uidlen) { + //case 10: flags |= FLAG_10B_UID_IN_DATA; break; + case 7: + flags |= FLAG_7B_UID_IN_DATA; + break; + case 4: + flags |= FLAG_4B_UID_IN_DATA; + break; + default: + errors = true; + break; + } + if (!errors) { + PrintAndLogEx(SUCCESS, "Emulating ISO/IEC 14443 type A tag with %d byte UID (%s)", uidlen, sprint_hex(uid, uidlen)); + useUIDfromEML = false; + } + cmdp += 2; + break; + case 'v': + verbose = true; + cmdp++; + break; + case 'x': + flags |= FLAG_NR_AR_ATTACK; + cmdp++; + break; + case 'e': + setEmulatorMem = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0) return usage_hf_14a_sim(); + + if (useUIDfromEML) + flags |= FLAG_UID_IN_EMUL; + + struct { + uint8_t tagtype; + uint8_t flags; + uint8_t uid[10]; + } PACKED payload; + + payload.tagtype = tagtype; + payload.flags = flags; + memcpy(payload.uid, uid, uidlen); + + clearCommandBuffer(); + SendCommandNG(CMD_SIMULATE_TAG_ISO_14443a, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + + PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); + + while (!ukbhit()) { + if (WaitForResponseTimeout(CMD_SIMULATE_MIFARE_CARD, &resp, 1500) == 0) continue; + if (resp.status != PM3_SUCCESS) break; + + if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) break; + + nonces_t *data = (nonces_t *)resp.data.asBytes; + readerAttack(data[0], setEmulatorMem, verbose); + } + if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) + showSectorTable(); + + PrintAndLogEx(INFO, "Done"); + return PM3_SUCCESS; } int CmdHF14ASniff(const char *Cmd) { - int param = 0; - uint8_t ctmp; - for (int i = 0; i < 2; i++) { - ctmp = param_getchar(Cmd, i); - if (ctmp == 'h' || ctmp == 'H') return usage_hf_14a_sniff(); - if (ctmp == 'c' || ctmp == 'C') param |= 0x01; - if (ctmp == 'r' || ctmp == 'R') param |= 0x02; - } - UsbCommand c = {CMD_SNOOP_ISO_14443a, {param, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + uint8_t param = 0; + for (uint8_t i = 0; i < 2; i++) { + uint8_t ctmp = tolower(param_getchar(Cmd, i)); + if (ctmp == 'h') return usage_hf_14a_sniff(); + if (ctmp == 'c') param |= 0x01; + if (ctmp == 'r') param |= 0x02; + } + clearCommandBuffer(); + SendCommandNG(CMD_SNIFF_ISO_14443a, (uint8_t *)¶m, sizeof(uint8_t)); + return PM3_SUCCESS; +} + +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + static uint8_t responseNum = 0; + uint16_t cmdc = 0; + *dataoutlen = 0; + + if (activateField) { + responseNum = 1; + PacketResponseNG resp; + + // Anticollision + SELECT card + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + return 1; + } + + // check result + if (resp.oldarg[0] == 0) { + PrintAndLogEx(ERR, "No card in field."); + return 1; + } + + if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { + PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.oldarg[0]); + return 1; + } + + if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // get ATS + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + SendCommandOLD(CMD_READER_ISO_14443a, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + return 1; + } + + if (resp.oldarg[0] == 0) { // ats_len + PrintAndLogEx(ERR, "Can't get ATS."); + return 1; + } + } + } + + if (leaveSignalON) + cmdc |= ISO14A_NO_DISCONNECT; + + uint8_t data[PM3_CMD_DATA_SIZE] = { 0x0a | responseNum, 0x00}; + responseNum ^= 1; + memcpy(&data[2], datain, datainlen & 0xFFFF); + SendCommandOLD(CMD_READER_ISO_14443a, ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0, data, (datainlen & 0xFFFF) + 2); + + uint8_t *recv; + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + recv = resp.data.asBytes; + int iLen = resp.oldarg[0]; + + if (!iLen) { + PrintAndLogEx(ERR, "No card response."); + return 1; + } + + *dataoutlen = iLen - 2; + if (*dataoutlen < 0) + *dataoutlen = 0; + + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { + PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + return 2; + } + + if (recv[0] != data[0]) { + PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); + return 2; + } + + memcpy(dataout, &recv[2], *dataoutlen); + + // CRC Check + if (iLen == -1) { + PrintAndLogEx(ERR, "ISO 14443A CRC error."); + return 3; + } + + } else { + PrintAndLogEx(ERR, "Reply timeout."); + return 4; + } + + return 0; +} + +static int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { + PacketResponseNG resp; + + frameLength = 0; + + if (card) + memset(card, 0, sizeof(iso14a_card_select_t)); + + DropField(); + + // Anticollision + SELECT card + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + return 1; + } + + // check result + if (resp.oldarg[0] == 0) { + PrintAndLogEx(ERR, "No card in field."); + return 1; + } + + if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { + PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.oldarg[0]); + return 1; + } + + if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // get ATS + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + SendCommandOLD(CMD_READER_ISO_14443a, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, sizeof(rats), 0, rats, sizeof(rats)); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + return 1; + } + + if (resp.oldarg[0] == 0) { // ats_len + PrintAndLogEx(ERR, "Can't get ATS."); + return 1; + } + + // get frame length from ATS in data field + if (resp.oldarg[0] > 1) { + uint8_t fsci = resp.data.asBytes[1] & 0x0f; + if (fsci < ARRAYLEN(atsFSC)) + frameLength = atsFSC[fsci]; + } + } else { + // get frame length from ATS in card data structure + iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.data.asBytes; + if (vcard->ats_len > 1) { + uint8_t fsci = vcard->ats[1] & 0x0f; + if (fsci < ARRAYLEN(atsFSC)) + frameLength = atsFSC[fsci]; + } + + if (card) + memcpy(card, vcard, sizeof(iso14a_card_select_t)); + } + + if (disconnect) + DropField(); + + return 0; +} + +static int CmdExchangeAPDU(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 PM3_CMD_DATA_SIZE=512 + // timeout must be authomatically set by "get ATS" + if (datain) + SendCommandOLD(CMD_READER_ISO_14443a, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0, datain, datainlen & 0xFFFF); + else + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, 0, 0, NULL, 0); + + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t *recv = resp.data.asBytes; + int iLen = resp.oldarg[0]; + uint8_t res = resp.oldarg[1]; + + int dlen = iLen - 2; + if (dlen < 0) + dlen = 0; + *dataoutlen += dlen; + + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { + PrintAndLogEx(ERR, "APDU: 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) { + PrintAndLogEx(ERR, "APDU: No APDU response."); + return 1; + } + + // check apdu length + if (iLen < 2 && iLen >= 0) { + PrintAndLogEx(ERR, "APDU: Small APDU response. Len=%d", iLen); + return 2; + } + + // check block TODO + if (iLen == -2) { + PrintAndLogEx(ERR, "APDU: Block type mismatch."); + return 2; + } + + memcpy(dataout, recv, dlen); + + // chaining + if ((res & 0x10) != 0) { + *chainingout = true; + } + + // CRC Check + if (iLen == -1) { + PrintAndLogEx(ERR, "APDU: ISO 14443A CRC error."); + return 3; + } + } else { + PrintAndLogEx(ERR, "APDU: Reply timeout."); + return 4; + } + + return 0; } int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - uint16_t cmdc = 0; - - if (activateField) { - cmdc |= ISO14A_CONNECT; - } - if (leaveSignalON) - cmdc |= ISO14A_NO_DISCONNECT; + *dataoutlen = 0; + bool chaining = false; + int res; - // "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 | cmdc, (datainlen & 0xFFFF), 0}}; - memcpy(c.d.asBytes, datain, datainlen); - SendCommand(&c); - - uint8_t *recv; - UsbCommand resp; + // 3 byte here - 1b framing header, 2b crc16 + if (APDUInFramingEnable && + ((frameLength && (datainlen > frameLength - 3)) || (datainlen > PM3_CMD_DATA_SIZE - 3))) { + int clen = 0; - if (activateField) { - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(NORMAL, "APDU ERROR: Proxmark connection timeout."); - return 1; - } - if (resp.arg[0] != 1) { - PrintAndLogEx(NORMAL, "APDU ERROR: Proxmark error %d.", resp.arg[0]); - return 1; - } - } + bool vActivateField = activateField; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - recv = resp.d.asBytes; - int iLen = resp.arg[0]; - - *dataoutlen = iLen - 2; - if (*dataoutlen < 0) - *dataoutlen = 0; - - if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLogEx(NORMAL, "APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); - return 2; - } - - memcpy(dataout, recv, *dataoutlen); - - if(!iLen) { - PrintAndLogEx(NORMAL, "APDU ERROR: No APDU response."); - return 1; - } + do { + int vlen = MIN(frameLength - 3, datainlen - clen); + bool chainBlockNotLast = ((clen + vlen) < datainlen); - // check block TODO - if (iLen == -2) { - PrintAndLogEx(NORMAL, "APDU ERROR: Block type mismatch."); - return 2; - } - - // CRC Check - if (iLen == -1) { - PrintAndLogEx(NORMAL, "APDU ERROR: ISO 14443A CRC error."); - return 3; - } + *dataoutlen = 0; + res = CmdExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (!leaveSignalON) + DropField(); - // check apdu length - if (iLen < 4) { - PrintAndLogEx(NORMAL, "APDU ERROR: Small APDU response. Len=%d", iLen); - return 2; - } - + return 200; + } + + // check R-block ACK +//TODO check this one... + if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { // *dataoutlen!=0. 'A && (!A || B)' is equivalent to 'A && B' + 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 { - PrintAndLogEx(NORMAL, "APDU ERROR: Reply timeout."); - return 4; + res = CmdExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (!leaveSignalON) + DropField(); + + return res; + } } - - return 0; + + while (chaining) { + // I-block with chaining + res = CmdExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + + if (res) { + if (!leaveSignalON) + DropField(); + + return 100; + } + } + + if (!leaveSignalON) + DropField(); + + return 0; } -int CmdHF14AAPDU(const char *cmd) { - uint8_t data[USB_CMD_DATA_SIZE]; - int datalen = 0; - bool activateField = false; - bool leaveSignalON = false; - bool decodeTLV = false; - - if (strlen(cmd) < 2) return usage_hf_14a_apdu(); +// ISO14443-4. 7. Half-duplex block transmission protocol +static int CmdHF14AAPDU(const char *Cmd) { + uint8_t data[PM3_CMD_DATA_SIZE]; + int datalen = 0; + bool activateField = false; + bool leaveSignalON = false; + bool decodeTLV = false; - int cmdp = 0; - while(param_getchar(cmd, cmdp) != 0x00) { - char c = param_getchar(cmd, cmdp); - if ((c == '-') && (param_getlength(cmd, cmdp) == 2)) - switch (tolower(param_getchar_indx(cmd, 1, cmdp))) { - case 'h': - return usage_hf_14a_apdu(); - case 's': - activateField = true; - break; - case 'k': - leaveSignalON = true; - break; - case 't': - decodeTLV = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp)); - return 1; - } - - if (isxdigit(c)) { - // len = data + PCB(1b) + CRC(2b) - switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data) - 1 - 2, &datalen)) { - case 1: - PrintAndLogEx(WARNING, "invalid HEX value."); - return 1; - case 2: - PrintAndLogEx(WARNING, "APDU too large."); - return 1; - case 3: - PrintAndLogEx(WARNING, "hex must have even number of digits."); - return 1; - } - - // we get all the hex to end of line with spaces - break; - } - - cmdp++; - } + CLIParserInit("hf 14a apdu", + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", + "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); - PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - - int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); + 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_strx1(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, false); - if (res) - return res; + activateField = arg_get_lit(1); + leaveSignalON = arg_get_lit(2); + decodeTLV = arg_get_lit(3); + // len = data + PCB(1b) + CRC(2b) + CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); - PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen)); - - PrintAndLogEx(SUCCESS, "APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); + CLIParserFree(); + PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel " : "", leaveSignalON ? "keep " : "", decodeTLV ? "TLV" : "", sprint_hex(data, datalen)); - // TLV decoder - if (decodeTLV && datalen > 4) { - TLVPrintFromBuffer(data, datalen - 2); - } - - return 0; + int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, PM3_CMD_DATA_SIZE, &datalen); + + if (res) + return res; + + PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(data, datalen)); + + PrintAndLogEx(SUCCESS, "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; } -int CmdHF14ACmdRaw(const char *cmd) { - UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; +static int CmdHF14ACmdRaw(const char *Cmd) { bool reply = 1; bool crc = false; bool power = false; bool active = false; bool active_select = false; - bool no_rats = false; + bool no_rats = false; uint16_t numbits = 0; - bool bTimeout = false; - uint32_t timeout = 0; - bool topazmode = false; - char buf[5]=""; + bool bTimeout = false; + uint32_t timeout = 0; + bool topazmode = false; + char buf[5] = ""; int i = 0; - uint8_t data[USB_CMD_DATA_SIZE]; - uint16_t datalen = 0; - uint32_t temp; + uint8_t data[PM3_CMD_DATA_SIZE]; + uint16_t datalen = 0; + uint32_t temp; - if (strlen(cmd) < 2) return usage_hf_14a_raw(); + if (strlen(Cmd) < 2) return usage_hf_14a_raw(); // strip - while (*cmd==' ' || *cmd=='\t') cmd++; + 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 'H': - case 'h': - return usage_hf_14a_raw(); - case 'r': + while (Cmd[i] != '\0') { + if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } + if (Cmd[i] == '-') { + switch (Cmd[i + 1]) { + case 'H': + case 'h': + return usage_hf_14a_raw(); + case 'r': reply = false; break; case 'c': @@ -860,49 +924,49 @@ int CmdHF14ACmdRaw(const char *cmd) { case 's': active_select = true; break; - case 'b': - sscanf(cmd+i+2, "%d", &temp); + case 'b': + sscanf(Cmd + i + 2, "%d", &temp); numbits = temp & 0xFFFF; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i-=2; + i += 3; + while (Cmd[i] != ' ' && Cmd[i] != '\0') { i++; } + i -= 2; + break; + case 't': + bTimeout = true; + sscanf(Cmd + i + 2, "%d", &temp); + timeout = temp; + i += 3; + while (Cmd[i] != ' ' && Cmd[i] != '\0') { i++; } + i -= 2; break; - case 't': - bTimeout = true; - sscanf(cmd+i+2, "%d", &temp); - timeout = temp; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i-=2; - break; case 'T': - topazmode = true; - break; - case '3': - no_rats = true; - break; + topazmode = true; + break; + case '3': + no_rats = true; + break; default: return usage_hf_14a_raw(); } 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]; + 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; - if (++datalen >= sizeof(data)){ - if (crc) - PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); - break; - } + if (++datalen >= sizeof(data)) { + if (crc) + PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); + break; + } } continue; } @@ -910,129 +974,465 @@ int CmdHF14ACmdRaw(const char *cmd) { return 0; } - if (crc && datalen > 0 && datalen < sizeof(data)-2) { + if (crc && datalen > 0 && datalen < sizeof(data) - 2) { uint8_t first, second; - if (topazmode) { - compute_crc(CRC_14443_B, data, datalen, &first, &second); - } else { - compute_crc(CRC_14443_A, data, datalen, &first, &second); - } + if (topazmode) { + compute_crc(CRC_14443_B, data, datalen, &first, &second); + } else { + compute_crc(CRC_14443_A, data, datalen, &first, &second); + } data[datalen++] = first; data[datalen++] = second; } + uint16_t flags = 0; if (active || active_select) { - c.arg[0] |= ISO14A_CONNECT; + flags |= ISO14A_CONNECT; if (active) - c.arg[0] |= ISO14A_NO_SELECT; + flags |= ISO14A_NO_SELECT; } - if (bTimeout){ - #define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s - c.arg[0] |= ISO14A_SET_TIMEOUT; - if(timeout > MAX_TIMEOUT) { + uint32_t argtimeout = 0; + if (bTimeout) { +#define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s + flags |= ISO14A_SET_TIMEOUT; + if (timeout > MAX_TIMEOUT) { timeout = MAX_TIMEOUT; PrintAndLogEx(NORMAL, "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) - } + argtimeout = 13560000 / 1000 / (8 * 16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) + } 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 - datalen = (datalen > USB_CMD_DATA_SIZE) ? USB_CMD_DATA_SIZE : datalen; - - c.arg[1] = (datalen & 0xFFFF) | ((uint32_t)(numbits << 16)); - memcpy(c.d.asBytes, data, datalen); + flags |= ISO14A_NO_DISCONNECT; + } - clearCommandBuffer(); - SendCommand(&c); + if (datalen > 0) { + flags |= ISO14A_RAW; + } + + if (topazmode) { + flags |= ISO14A_TOPAZMODE; + } + if (no_rats) { + flags |= ISO14A_NO_RATS; + } + + // Max buffer is PM3_CMD_DATA_SIZE + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; + + clearCommandBuffer(); + SendCommandOLD(CMD_READER_ISO_14443a, flags, (datalen & 0xFFFF) | ((uint32_t)(numbits << 16)), argtimeout, data, datalen & 0xFFFF); if (reply) { - int res = 0; + int res = 0; if (active_select) - res = waitCmd(1); - if (!res && datalen > 0) + res = waitCmd(1); + if (!res && datalen > 0) waitCmd(0); } return 0; } static int waitCmd(uint8_t iSelect) { - UsbCommand resp; - uint16_t len = 0; + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint16_t len = (resp.oldarg[0] & 0xFFFF); + if (iSelect) { + len = (resp.oldarg[1] & 0xFFFF); + if (len) { + PrintAndLogEx(NORMAL, "Card selected. UID[%i]:", len); + } else { + PrintAndLogEx(WARNING, "Can't select card."); + } + } else { + PrintAndLogEx(NORMAL, "received %i bytes", len); + } - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - len = (resp.arg[0] & 0xFFFF); - if (iSelect){ - len = (resp.arg[1] & 0xFFFF); - if (len){ - PrintAndLogEx(NORMAL, "Card selected. UID[%i]:", len); - } else { - PrintAndLogEx(WARNING, "Can't select card."); - } - } else { - PrintAndLogEx(NORMAL, "received %i bytes", len); - } - if (!len) return 1; - - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.d.asBytes, len) ); + + PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 3; + return 3; } - return 0; + return 0; } -int CmdHF14AAntiFuzz(const char *cmd) { - - if (strlen(cmd) < 1) return usage_hf_14a_antifuzz(); +static int CmdHF14AAntiFuzz(const char *Cmd) { - // read param length - uint8_t arg0 = 4; - - UsbCommand c = {CMD_ANTIFUZZ_ISO_14443a, {arg0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + CLIParserInit("hf 14a antifuzz", + "Tries to fuzz the ISO14443a anticollision phase", + "Usage:\n" + "\thf 14a antifuzz -4\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("4", NULL, "4 byte uid"), + arg_lit0("7", NULL, "7 byte uid"), + arg_lit0(NULL, "10", "10 byte uid"), + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, false); + + uint8_t arg0 = FLAG_4B_UID_IN_DATA; + if (arg_get_lit(2)) + arg0 = FLAG_7B_UID_IN_DATA; + if (arg_get_lit(3)) + arg0 = FLAG_10B_UID_IN_DATA; + + CLIParserFree(); + clearCommandBuffer(); + SendCommandMIX(CMD_ANTIFUZZ_ISO_14443a, arg0, 0, 0, NULL, 0); + return 0; +} + +static int CmdHF14AChaining(const char *Cmd) { + + CLIParserInit("hf 14a chaining", + "Enable/Disable ISO14443a input chaining. Maximum input length goes from ATS.", + "Usage:\n" + "\thf 14a chaining disable -> disable chaining\n" + "\thf 14a chaining -> show chaining enable/disable state\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, true); + + struct arg_str *str = arg_get_str(1); + int len = arg_get_str_len(1); + + if (len && (!strcmp(str->sval[0], "enable") || !strcmp(str->sval[0], "1"))) + APDUInFramingEnable = true; + + if (len && (!strcmp(str->sval[0], "disable") || !strcmp(str->sval[0], "0"))) + APDUInFramingEnable = false; + + CLIParserFree(); + + PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); + + return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443-a history"}, - {"info", CmdHF14AInfo, 0, "Tag information"}, - {"reader", CmdHF14AReader, 0, "Act like an ISO14443-a reader"}, - {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443-a UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443-a tag"}, - {"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"}, - {"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"}, - {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, - {"antifuzz", CmdHF14AAntiFuzz, 0, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHF14AList, AlwaysAvailable, "List ISO 14443-a history"}, + {"info", CmdHF14AInfo, IfPm3Iso14443a, "Tag information"}, + {"reader", CmdHF14AReader, IfPm3Iso14443a, "Act like an ISO14443-a reader"}, + {"cuids", CmdHF14ACUIDs, IfPm3Iso14443a, " Collect n>0 ISO14443-a UIDs in one go"}, + {"sim", CmdHF14ASim, IfPm3Iso14443a, " -- Simulate ISO 14443-a tag"}, + {"sniff", CmdHF14ASniff, IfPm3Iso14443a, "sniff ISO 14443-a traffic"}, + {"apdu", CmdHF14AAPDU, IfPm3Iso14443a, "Send ISO 14443-4 APDU to tag"}, + {"chaining", CmdHF14AChaining, IfPm3Iso14443a, "Control ISO 14443-4 input chaining"}, + {"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, + {"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, + {NULL, NULL, NULL, NULL} }; -int CmdHF14A(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +int CmdHF14A(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } + +int infoHF14A(bool verbose, bool do_nack_test) { + clearCommandBuffer(); + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (verbose) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + return 0; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + /* + 0: couldn't read + 1: OK, with ATS + 2: OK, no ATS + 3: proprietary Anticollision + */ + uint64_t select_status = resp.oldarg[0]; + + if (select_status == 0) { + if (verbose) PrintAndLogEx(WARNING, "iso14443a card select failed"); + DropField(); + return select_status; + } + + if (select_status == 3) { + PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + DropField(); + return select_status; + } + + PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + + bool isMifareClassic = true; + switch (card.sak) { + case 0x00: + isMifareClassic = false; + + // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) + DropField(); + + uint32_t tagT = GetHF14AMfU_Type(); + if (tagT != UL_ERROR) + ul_print_type(tagT, 0); + else + PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)"); + + // reconnect for further tests + clearCommandBuffer(); + SendCommandMIX(CMD_READER_ISO_14443a, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + WaitForResponse(CMD_ACK, &resp); + + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS + + if (select_status == 0) { + DropField(); + return select_status; + } + break; + case 0x01: + PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance"); + break; + case 0x04: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); + isMifareClassic = false; + break; + case 0x08: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); + break; + case 0x09: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k"); + break; + case 0x0A: + PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)"); + break; + case 0x10: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2"); + break; + case 0x11: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2"); + break; + case 0x18: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); + break; + case 0x20: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); + isMifareClassic = false; + break; + case 0x24: + PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1"); + isMifareClassic = false; + break; + case 0x28: + PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1"); + break; + case 0x38: + PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); + break; + case 0x88: + PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K"); + break; + case 0x98: + PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS"); + break; + default: + ; + } + + // Double & triple sized UID, can be mapped to a manufacturer. + if (card.uidlen > 4) { + PrintAndLogEx(NORMAL, "MANUFACTURER : %s", getTagInfo(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 + clearCommandBuffer(); + SendCommandOLD(CMD_READER_ISO_14443a, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); + WaitForResponse(CMD_ACK, &resp); + + memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); + card.ats_len = resp.oldarg[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 + bool ta1 = 0, tb1 = 0, tc1 = 0; + int pos; + + if (select_status == 2) { + PrintAndLogEx(NORMAL, "SAK incorrectly claims that card doesn't support RATS"); + } + PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]); + if (card.ats[0] != card.ats_len - 2) { + PrintAndLogEx(NORMAL, "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; + + PrintAndLogEx(NORMAL, " - T0 : TA1 is%s present, TB1 is%s present, " + "TC1 is%s present, FSCI is %d (FSC = %ld)", + (ta1 ? "" : " NOT"), + (tb1 ? "" : " NOT"), + (tc1 ? "" : " NOT"), + fsci, + fsci < ARRAYLEN(atsFSC) ? atsFSC[fsci] : -1 + ); + } + pos = 2; + if (ta1) { + 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 (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; + if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; + PrintAndLogEx(NORMAL, " - TA1 : different divisors are%s supported, " + "DR: [%s], DS: [%s]", + ((card.ats[pos] & 0x80) ? " NOT" : ""), + dr, + ds + ); + + pos++; + } + if (tb1) { + uint32_t sfgi = card.ats[pos] & 0x0F; + uint32_t fwi = card.ats[pos] >> 4; + PrintAndLogEx(NORMAL, " - 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 + ); + pos++; + } + if (tc1) { + PrintAndLogEx(NORMAL, " - TC1 : NAD is%s supported, CID is%s supported", + (card.ats[pos] & 0x01) ? "" : " NOT", + (card.ats[pos] & 0x02) ? "" : " NOT"); + pos++; + } + if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) { + const char *tip = ""; + if (card.ats[0] - 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) { + tip = "-> MIFARE Plus S 2K or 4K"; + } + } + PrintAndLogEx(NORMAL, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); + if (card.ats[pos] == 0xC1) { + PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type"); + PrintAndLogEx(NORMAL, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); + switch (card.ats[pos + 2] & 0xf0) { + case 0x10: + PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire"); + break; + case 0x20: + PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus"); + break; + } + switch (card.ats[pos + 2] & 0x0f) { + case 0x00: + PrintAndLogEx(NORMAL, " x0 -> <1 kByte"); + break; + case 0x01: + PrintAndLogEx(NORMAL, " x1 -> 1 kByte"); + break; + case 0x02: + PrintAndLogEx(NORMAL, " x2 -> 2 kByte"); + break; + case 0x03: + PrintAndLogEx(NORMAL, " x3 -> 4 kByte"); + break; + case 0x04: + PrintAndLogEx(NORMAL, " x4 -> 8 kByte"); + break; + } + switch (card.ats[pos + 3] & 0xf0) { + case 0x00: + PrintAndLogEx(NORMAL, " 0x -> Engineering sample"); + break; + case 0x20: + PrintAndLogEx(NORMAL, " 2x -> Released"); + break; + } + switch (card.ats[pos + 3] & 0x0f) { + case 0x00: + PrintAndLogEx(NORMAL, " x0 -> Generation 1"); + break; + case 0x01: + PrintAndLogEx(NORMAL, " x1 -> Generation 2"); + break; + case 0x02: + PrintAndLogEx(NORMAL, " x2 -> Generation 3"); + break; + } + switch (card.ats[pos + 4] & 0x0f) { + case 0x00: + PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported"); + break; + case 0x01: + PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported"); + break; + case 0x0E: + PrintAndLogEx(NORMAL, " xE -> no VCS command supported"); + break; + } + } + } + } else { + PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); + } + + detect_classic_magic(); + + if (isMifareClassic) { + int res = detect_classic_prng(); + if (res == 1) + PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("WEAK")); + else if (res == 0) + PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("HARD")); + else + PrintAndLogEx(FAILED, "prng detection: " _RED_("Fail")); + + if (do_nack_test) + detect_classic_nackbug(!verbose); + } + + return select_status; +} + diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index b2ae5896e..d5626d995 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -24,36 +24,28 @@ #include "util.h" #include "cmdparser.h" #include "cmdmain.h" -#include "iso14443crc.h" #include "mifare.h" #include "cmdhfmf.h" #include "cmdhfmfu.h" -#include "cmdhf.h" // list cmd -#include "mifarehost.h" +#include "cmdhf.h" // list cmd +#include "mifare/mifarehost.h" #include "emv/apduinfo.h" -#include "emv/emvcore.h" +#include "emv/emvcore.h" -// structure and database for uid -> tagtype lookups -typedef struct { - uint8_t uid; - char* desc; -} manufactureName; +// structure and database for uid -> tagtype lookups +typedef struct { + uint8_t uid; + const char *desc; +} manufactureName; -extern int CmdHF14A(const char *Cmd); -extern int CmdHF14AList(const char *Cmd); -extern int CmdHF14AReader(const char *Cmd); -extern int CmdHF14AInfo(const char *Cmd); -extern int CmdHF14ASim(const char *Cmd); -extern int CmdHF14ASniff(const char *Cmd); -extern int CmdHF14ACmdRaw(const char *Cmd); -extern int CmdHF14ACUIDs(const char *Cmd); -extern int CmdHF14AAntiFuzz(const char *cmd); +int CmdHF14A(const char *Cmd); +int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff +int CmdHF14ASim(const char *Cmd); // used by hf mfu sim -extern char* getTagInfo(uint8_t uid); -extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int infoHF14A(bool verbose, bool do_nack_test); +const char *getTagInfo(uint8_t uid); +int Hf14443_4aGetCardData(iso14a_card_select_t *card); +int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -extern int usage_hf_14a_sim(void); -extern int usage_hf_14a_sniff(void); -extern int usage_hf_14a_raw(void); -extern int usage_hf_14a_antifuzz(void); #endif diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 4077e16e6..c95494b7a 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -14,279 +14,324 @@ #define TIMEOUT 2000 static int CmdHelp(const char *Cmd); -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; +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 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 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; } -int usage_hf_14b_raw(void){ - PrintAndLogEx(NORMAL, "Usage: hf 14b raw [-h] [-r] [-c] [-p] [-s || -ss] <0A 0B 0C ... hex>"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " -h this help"); - PrintAndLogEx(NORMAL, " -r do not read response"); - PrintAndLogEx(NORMAL, " -c calculate and append CRC"); - PrintAndLogEx(NORMAL, " -p leave the field on after receive"); - PrintAndLogEx(NORMAL, " -s active signal field ON with select"); - PrintAndLogEx(NORMAL, " -ss active signal field ON with select for SRx ST Microelectronics tags"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b raw -s -c -p 0200a40400"); - return 0; +static int usage_hf_14b_raw(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14b raw [-h] [-r] [-c] [-p] [-s / -ss] [-t] <0A 0B 0C ... hex>"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -r do not read response"); + PrintAndLogEx(NORMAL, " -c calculate and append CRC"); + PrintAndLogEx(NORMAL, " -p leave the field on after receive"); + PrintAndLogEx(NORMAL, " -s active signal field ON with select"); + PrintAndLogEx(NORMAL, " -ss active signal field ON with select for SRx ST Microelectronics tags"); + PrintAndLogEx(NORMAL, " -t timeout in ms"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b raw -s -c -p 0200a40400"); + return 0; } -int usage_hf_14b_sniff(void){ - PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); - PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list 14b'"); - PrintAndLogEx(NORMAL, "Usage: hf 14b sniff [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b sniff"); - return 0; +static int usage_hf_14b_sniff(void) { + PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); + PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list 14b'"); + PrintAndLogEx(NORMAL, "Usage: hf 14b sniff [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b sniff"); + return 0; } -int usage_hf_14b_sim(void){ - PrintAndLogEx(NORMAL, "Emulating ISO/IEC 14443 type B tag with 4 UID / PUPI"); - PrintAndLogEx(NORMAL, "Usage: hf 14b sim [h] u "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " u 4byte UID/PUPI"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b sim"); - PrintAndLogEx(NORMAL, " hf 14b sim u 11223344"); - return 0; +static int usage_hf_14b_sim(void) { + PrintAndLogEx(NORMAL, "Emulating ISO/IEC 14443 type B tag with 4 UID / PUPI"); + PrintAndLogEx(NORMAL, "Usage: hf 14b sim [h] u "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " u 4byte UID/PUPI"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b sim"); + PrintAndLogEx(NORMAL, " hf 14b sim u 11223344"); + return 0; } -int usage_hf_14b_read_srx(void){ - PrintAndLogEx(NORMAL, "Usage: hf 14b sriread [h] <1|2>"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b sriread 1"); - PrintAndLogEx(NORMAL, " hf 14b sriread 2"); - return 0; +static int usage_hf_14b_read_srx(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14b sriread [h] <1|2>"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b sriread 1"); + PrintAndLogEx(NORMAL, " hf 14b sriread 2"); + return 0; } -int usage_hf_14b_write_srx(void){ - PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); - PrintAndLogEx(NORMAL, " BLOCK number depends on tag, special block == FF"); - PrintAndLogEx(NORMAL, " hex bytes of data to be written"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 7F 11223344"); - PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 FF 11223344"); - PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 15 11223344"); - PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 FF 11223344"); - return 0; +static int usage_hf_14b_write_srx(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512"); + PrintAndLogEx(NORMAL, " BLOCK number depends on tag, special block == FF"); + PrintAndLogEx(NORMAL, " hex bytes of data to be written"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 7F 11223344"); + PrintAndLogEx(NORMAL, " hf 14b sriwrite 1 FF 11223344"); + PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 15 11223344"); + PrintAndLogEx(NORMAL, " hf 14b sriwrite 2 FF 11223344"); + return 0; } -int usage_hf_14b_dump(void){ - PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n" - "\n" - "Usage: hf 14b dump [h] [card memory] \n" - "Options:\n" - "\th this help\n" - "\t[card memory] 1 = SRIX4K (default), 2 = SRI512" - "\tf filename, if no UID will be used as filename\n" - "\n" - "Example:\n" - "\thf 14b dump f\n" - "\thf 14b dump 2 f mydump"); - return 0; +static int usage_hf_14b_dump(void) { + PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n" + "\n" + "Usage: hf 14b dump [h] [card memory] \n" + "Options:\n" + "\th this help\n" + "\t[card memory] 1 = SRIX4K (default), 2 = SRI512" + "\tf filename, if no UID will be used as filename\n" + "\n" + "Example:\n" + "\thf 14b dump f\n" + "\thf 14b dump 2 f mydump"); + return 0; } /* static void switch_on_field_14b(void) { - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT, 0, 0, NULL, 0); } */ static int switch_off_field_14b(void) { - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_DISCONNECT, 0, 0, NULL, 0); + return 0; } -int CmdHF14BList(const char *Cmd) { - CmdTraceList("14b"); - return 0; +static bool waitCmd14b(bool verbose) { + + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + + if ((resp.oldarg[0] & 0xFF) > 0) return false; + + uint16_t len = (resp.oldarg[1] & 0xFFFF); + + uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; + memcpy(data, resp.data.asBytes, len); + + if (verbose) { + if (len >= 3) { + bool crc = check_crc(CRC_14443_B, data, len); + + PrintAndLogEx(NORMAL, "[LEN %u] %s[%02X %02X] %s", + len, + sprint_hex(data, len - 2), + data[len - 2], + data[len - 1], + (crc) ? "OK" : "FAIL" + ); + } else { + PrintAndLogEx(NORMAL, "[LEN %u] %s", len, sprint_hex(data, len)); + } + } + return true; + } else { + PrintAndLogEx(WARNING, "command execution timeout"); + return false; + } } -int CmdHF14BSim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_14b_sim(); - - uint32_t pupi = 0; - if (cmdp == 'u') { - pupi = param_get32ex(Cmd, 1, 0, 16); - } - - UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443B, {pupi, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; +static int CmdHF14BList(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdTraceList("14b"); + return 0; } -int CmdHF14BSniff(const char *Cmd) { - - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_14b_sniff(); - - UsbCommand c = {CMD_SNOOP_ISO_14443B, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; +static int CmdHF14BSim(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_14b_sim(); + + uint32_t pupi = 0; + if (cmdp == 'u') { + pupi = param_get32ex(Cmd, 1, 0, 16); + } + + clearCommandBuffer(); + SendCommandMIX(CMD_SIMULATE_TAG_ISO_14443B, pupi, 0, 0, NULL, 0); + return 0; } -int CmdHF14BCmdRaw (const char *Cmd) { - bool reply = true, power = false, select = false; - char buf[5] = ""; - int i = 0; - uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; - uint16_t datalen = 0; - uint32_t flags = ISO14B_CONNECT; - uint32_t temp = 0; - - if ( strlen(Cmd) < 3 ) return usage_hf_14b_raw(); +static int CmdHF14BSniff(const char *Cmd) { + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_14b_sniff(); + + clearCommandBuffer(); + SendCommandNG(CMD_SNIFF_ISO_14443B, NULL, 0); + return 0; +} + +static int CmdHF14BCmdRaw(const char *Cmd) { + bool reply = true, power = false, select = false, hasTimeout = false; + char buf[5] = ""; + int i = 0; + uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; + uint16_t datalen = 0; + uint32_t flags = ISO14B_CONNECT; + uint32_t temp = 0, user_timeout = 0, time_wait = 0; + + if (strlen(Cmd) < 3) return usage_hf_14b_raw(); // strip - while (*Cmd==' ' || *Cmd=='\t') ++Cmd; - - while (Cmd[i]!='\0') { - if (Cmd[i]==' ' || Cmd[i]=='\t') { ++i; continue; } - if (Cmd[i]=='-') { - switch (tolower(Cmd[i+1])) { - case 'h': - return usage_hf_14b_raw(); - case 'r': + while (*Cmd == ' ' || *Cmd == '\t') ++Cmd; + + while (Cmd[i] != '\0') { + if (Cmd[i] == ' ' || Cmd[i] == '\t') { ++i; continue; } + if (Cmd[i] == '-') { + switch (tolower(Cmd[i + 1])) { + case 'h': + return usage_hf_14b_raw(); + case 'r': reply = false; break; case 'c': flags |= ISO14B_APPEND_CRC; break; - case 'p': - power = true; + case 'p': + power = true; + break; + case 's': + select = true; + if (tolower(Cmd[i + 2]) == 's') { + flags |= ISO14B_SELECT_SR; + ++i; + } else { + flags |= ISO14B_SELECT_STD; + } + break; + case 't': + hasTimeout = true; + sscanf(Cmd + i + 2, "%d", &user_timeout); + i += 3; + while (Cmd[i] != ' ' && Cmd[i] != '\0') { i++; } + i -= 2; break; - case 's': - select = true; - if (tolower(Cmd[i+2]) == 's') { - flags |= ISO14B_SELECT_SR; - ++i; - } else { - flags |= ISO14B_SELECT_STD; - } - break; default: return usage_hf_14b_raw(); } - i+=2; + 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]; + 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); + + if (strlen(buf) >= 2) { + sscanf(buf, "%x", &temp); data[datalen++] = (uint8_t)(temp & 0xff); - *buf=0; - memset(buf, 0x00, sizeof(buf)); + *buf = 0; + memset(buf, 0x00, sizeof(buf)); } continue; } PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, i)); - return 0; + return 0; } - - if (!power) + + if (hasTimeout) { +#define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s + flags |= ISO14B_SET_TIMEOUT; + if (user_timeout > MAX_TIMEOUT) { + user_timeout = MAX_TIMEOUT; + PrintAndLogEx(NORMAL, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); + } + time_wait = 13560000 / 1000 / (8 * 16) * user_timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) + } + + if (power == 0) flags |= ISO14B_DISCONNECT; if (datalen > 0) - flags |= ISO14B_RAW; + flags |= ISO14B_RAW; - // Max buffer is USB_CMD_DATA_SIZE - datalen = (datalen > USB_CMD_DATA_SIZE) ? USB_CMD_DATA_SIZE : datalen; + // Max buffer is PM3_CMD_DATA_SIZE + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; - UsbCommand c = {CMD_ISO_14443B_COMMAND, {flags, datalen, 0}}; - memcpy(c.d.asBytes, data, datalen); - clearCommandBuffer(); - SendCommand(&c); + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_14443B_COMMAND, flags, datalen, time_wait, data, datalen); - if (!reply) return 1; + if (!reply) return 1; - bool success = true; - // get back iso14b_card_select_t, don't print it. - if (select) - success = waitCmd14b(false); + bool success = true; + // get back iso14b_card_select_t, don't print it. + if (select) + success = waitCmd14b(false); - // get back response from the raw bytes you sent. - if (success && datalen>0) waitCmd14b(true); + // get back response from the raw bytes you sent. + if (success && datalen > 0) waitCmd14b(true); return 1; } static bool get_14b_UID(iso14b_card_select_t *card) { - if (!card) - return false; - - uint8_t retry = 3; - UsbCommand resp; - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}}; - - // test for 14b SR - while (retry--) { + if (!card) + return false; - clearCommandBuffer(); - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - - uint8_t status = resp.arg[0]; - if ( status == 0) { - memcpy(card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - return true; - } - } - } // retry + int8_t retry = 3; + PacketResponseNG resp; - // test 14b standard - c.arg[0] = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT; - retry = 3; - while (retry--) { + // test for 14b SR + while (retry--) { + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - clearCommandBuffer(); - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - - uint8_t status = resp.arg[0]; - if ( status == 0) { - memcpy(card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - return true; - } - } - } // retry - - if ( !retry ) - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - - return false; + uint8_t status = resp.oldarg[0]; + if (status == 0) { + memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + return true; + } + } + } // retry + + // test 14b standard + retry = 3; + while (retry--) { + + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + + uint8_t status = resp.oldarg[0]; + if (status == 0) { + memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + return true; + } + } + } // retry + + if (retry <= 0) + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + + return false; } // print full atqb info @@ -295,123 +340,140 @@ static bool get_14b_UID(iso14b_card_select_t *card) { // 4 = bit rate capacity // 5 = max frame size / -4 info // 6 = FWI / Coding options -static void print_atqb_resp(uint8_t *data, uint8_t cid){ - //PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(data+1,4)); - PrintAndLogEx(NORMAL, " App Data: %s", sprint_hex(data,4)); - PrintAndLogEx(NORMAL, " Protocol: %s", sprint_hex(data+4,3)); - uint8_t BitRate = data[4]; - if (!BitRate) PrintAndLogEx(NORMAL, " Bit Rate: 106 kbit/s only PICC <-> PCD"); - if (BitRate & 0x10) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC -> PCD supported"); - if (BitRate & 0x20) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC -> PCD supported"); - if (BitRate & 0x40) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC -> PCD supported"); - if (BitRate & 0x01) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC <- PCD supported"); - if (BitRate & 0x02) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC <- PCD supported"); - if (BitRate & 0x04) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC <- PCD supported"); - if (BitRate & 0x80) PrintAndLogEx(NORMAL, " Same bit rate <-> required"); +static void print_atqb_resp(uint8_t *data, uint8_t cid) { + //PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(data+1,4)); + PrintAndLogEx(NORMAL, " App Data: %s", sprint_hex(data, 4)); + PrintAndLogEx(NORMAL, " Protocol: %s", sprint_hex(data + 4, 3)); + uint8_t BitRate = data[4]; + if (!BitRate) PrintAndLogEx(NORMAL, " Bit Rate: 106 kbit/s only PICC <-> PCD"); + if (BitRate & 0x10) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC -> PCD supported"); + if (BitRate & 0x20) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC -> PCD supported"); + if (BitRate & 0x40) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC -> PCD supported"); + if (BitRate & 0x01) PrintAndLogEx(NORMAL, " Bit Rate: 212 kbit/s PICC <- PCD supported"); + if (BitRate & 0x02) PrintAndLogEx(NORMAL, " Bit Rate: 424 kbit/s PICC <- PCD supported"); + if (BitRate & 0x04) PrintAndLogEx(NORMAL, " Bit Rate: 847 kbit/s PICC <- PCD supported"); + if (BitRate & 0x80) PrintAndLogEx(NORMAL, " Same bit rate <-> required"); - uint16_t maxFrame = data[5] >> 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; - - PrintAndLogEx(NORMAL, "Max Frame Size: %u%s bytes", maxFrame, (maxFrame == 257) ? "+ RFU" : ""); + uint16_t maxFrame = data[5] >> 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; - uint8_t protocolT = data[5] & 0xF; - PrintAndLogEx(NORMAL, " Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4",(protocolT) ? "" : "not " ); - - uint8_t fwt = data[6]>>4; - if ( fwt < 16 ){ - uint32_t etus = (32 << fwt); - uint32_t fwt_time = (302 << fwt); - PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - %u ETUs | %u us", fwt, etus, fwt_time); - } else { - PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - RFU", fwt); - } - - PrintAndLogEx(NORMAL, " App Data Code: Application is %s",(data[6]&4) ? "Standard" : "Proprietary"); - PrintAndLogEx(NORMAL, " Frame Options: NAD is %ssupported",(data[6]&2) ? "" : "not "); - PrintAndLogEx(NORMAL, " Frame Options: CID is %ssupported",(data[6]&1) ? "" : "not "); - PrintAndLogEx(NORMAL, "Tag :"); - PrintAndLogEx(NORMAL, " Max Buf Length: %u (MBLI) %s", cid>>4, (cid & 0xF0) ? "" : "chained frames not supported"); - PrintAndLogEx(NORMAL, " CID : %u", cid & 0x0f); - return; + PrintAndLogEx(NORMAL, "Max Frame Size: %u%s bytes", maxFrame, (maxFrame == 257) ? "+ RFU" : ""); + + uint8_t protocolT = data[5] & 0xF; + PrintAndLogEx(NORMAL, " Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4", (protocolT) ? "" : "not "); + + uint8_t fwt = data[6] >> 4; + if (fwt < 16) { + uint32_t etus = (32 << fwt); + uint32_t fwt_time = (302 << fwt); + PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - %u ETUs | %u us", fwt, etus, fwt_time); + } else { + PrintAndLogEx(NORMAL, "Frame Wait Integer: %u - RFU", fwt); + } + + PrintAndLogEx(NORMAL, " App Data Code: Application is %s", (data[6] & 4) ? "Standard" : "Proprietary"); + PrintAndLogEx(NORMAL, " Frame Options: NAD is %ssupported", (data[6] & 2) ? "" : "not "); + PrintAndLogEx(NORMAL, " Frame Options: CID is %ssupported", (data[6] & 1) ? "" : "not "); + PrintAndLogEx(NORMAL, "Tag :"); + PrintAndLogEx(NORMAL, " Max Buf Length: %u (MBLI) %s", cid >> 4, (cid & 0xF0) ? "" : "chained frames not supported"); + PrintAndLogEx(NORMAL, " CID : %u", cid & 0x0f); + return; } // get SRx chip model (from UID) // from ST Microelectronics -char *get_ST_Chip_Model(uint8_t data){ - static char model[20]; - char *retStr = model; - memset(model,0, sizeof(model)); +static char *get_ST_Chip_Model(uint8_t data) { + static char model[20]; + char *retStr = model; + memset(model, 0, sizeof(model)); - switch (data) { - case 0x0: sprintf(retStr, "SRIX4K (Special)"); break; - case 0x2: sprintf(retStr, "SR176"); break; - case 0x3: sprintf(retStr, "SRIX4K"); break; - case 0x4: sprintf(retStr, "SRIX512"); break; - case 0x6: sprintf(retStr, "SRI512"); break; - case 0x7: sprintf(retStr, "SRI4K"); break; - case 0xC: sprintf(retStr, "SRT512"); break; - default : sprintf(retStr, "Unknown"); break; - } - return retStr; + switch (data) { + case 0x0: + sprintf(retStr, "SRIX4K (Special)"); + break; + case 0x2: + sprintf(retStr, "SR176"); + break; + case 0x3: + sprintf(retStr, "SRIX4K"); + break; + case 0x4: + sprintf(retStr, "SRIX512"); + break; + case 0x6: + sprintf(retStr, "SRI512"); + break; + case 0x7: + sprintf(retStr, "SRI4K"); + break; + case 0xC: + sprintf(retStr, "SRT512"); + break; + default : + sprintf(retStr, "Unknown"); + break; + } + return retStr; } // REMAKE: -int print_ST_Lock_info(uint8_t model){ +/* +static int print_ST_Lock_info(uint8_t model) { - // PrintAndLogEx(NORMAL, "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; - // PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+3, 1)); - // PrintAndLogEx(NORMAL, " 07/08:%slocked", (data[3] & 1) ? " not " : " " ); - // for (uint8_t i = 1; i<8; i++){ - // PrintAndLogEx(NORMAL, " %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; - // PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 2)); - // for (uint8_t b=2; b<4; b++){ - // for (uint8_t i=0; i<8; i++){ - // PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " ); - // blk1++; - // } - // } - // break; - // case 0x2: // (SR176) - // //need data[2] - // blk1 = 0; - // PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 1)); - // for (uint8_t i = 0; i<8; i++){ - // PrintAndLogEx(NORMAL, " %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " ); - // blk1+=2; - // } - // break; - // default: - // return rawClose(); - // } - return 1; + PrintAndLogEx(NORMAL, "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; + PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+3, 1)); + PrintAndLogEx(NORMAL, " 07/08:%slocked", (data[3] & 1) ? " not " : " " ); + for (uint8_t i = 1; i<8; i++){ + PrintAndLogEx(NORMAL, " %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; + PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 2)); + for (uint8_t b=2; b<4; b++){ + for (uint8_t i=0; i<8; i++){ + PrintAndLogEx(NORMAL, " %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " ); + blk1++; + } + } + break; + case 0x2: // (SR176) + //need data[2] + blk1 = 0; + PrintAndLogEx(NORMAL, " raw: %s", sprint_bin(data+2, 1)); + for (uint8_t i = 0; i<8; i++){ + PrintAndLogEx(NORMAL, " %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " ); + blk1+=2; + } + break; + default: + return rawClose(); + } + return 1; } - +*/ // print UID info from SRx chips (ST Microelectronics) -static void print_st_general_info(uint8_t *data, uint8_t len){ - //uid = first 8 bytes in data - PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(SwapEndian64(data,8,8), len)); - PrintAndLogEx(NORMAL, " MFG: %02X, %s", data[6], getTagInfo(data[6])); - PrintAndLogEx(NORMAL, "Chip: %02X, %s", data[5]>>2, get_ST_Chip_Model(data[5]>>2)); - return; +static void print_st_general_info(uint8_t *data, uint8_t len) { + //uid = first 8 bytes in data + PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(SwapEndian64(data, 8, 8), len)); + PrintAndLogEx(NORMAL, " MFG: %02X, %s", data[6], getTagInfo(data[6])); + PrintAndLogEx(NORMAL, "Chip: %02X, %s", data[5] >> 2, get_ST_Chip_Model(data[5] >> 2)); + return; } //05 00 00 = find one tag in field @@ -429,688 +491,643 @@ static void print_st_general_info(uint8_t *data, uint8_t len){ // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c]) //03 = ? (resp 03 [e3 c2]) //c2 = ? (resp c2 [66 15]) -//b2 = ? (resp a3 [e9 67]) +//b2 = ? (resp a3 [e9 67]) //a2 = ? (resp 02 [6a d3]) // 14b get and print Full Info (as much as we know) -bool HF14B_Std_Info(bool verbose){ +static bool HF14B_Std_Info(bool verbose) { - bool isSuccess = false; - - // 14b get and print UID only (general info) - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); - switch_off_field_14b(); - return false; + bool isSuccess = false; + + // 14b get and print UID only (general info) + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + switch_off_field_14b(); + return false; } - - iso14b_card_select_t card; - memcpy(&card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - - uint64_t status = resp.arg[0]; - - switch( status ){ - case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); - print_atqb_resp(card.atqb, card.cid); - isSuccess = true; - case 2: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); - break; - case 3: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); - break; - default: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); - break; - } - - return isSuccess; + + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 0: + PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + print_atqb_resp(card.atqb, card.cid); + isSuccess = true; + break; + case 2: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); + break; + case 3: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + default: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); + break; + } + + return isSuccess; } // SRx get and print full info (needs more info...) -bool HF14B_ST_Info(bool verbose){ - - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; +static bool HF14B_ST_Info(bool verbose) { - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); - return false; + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + return false; } - iso14b_card_select_t card; - memcpy(&card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - - uint64_t status = resp.arg[0]; - if ( status > 0 ) - return false; + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); - print_st_general_info(card.uid, card.uidlen); + uint64_t status = resp.oldarg[0]; + if (status > 0) + return false; - //add locking bit information here. uint8_t data[16] = {0x00}; - // uint8_t datalen = 2; - // uint8_t resplen; - // uint8_t blk1; - // data[0] = 0x08; + print_st_general_info(card.uid, card.uidlen); - // - // if (model == 0x2) { //SR176 has special command: - // data[1] = 0xf; - // resplen = 4; - // } else { - // data[1] = 0xff; - // resplen = 6; - // } + //add locking bit information here. uint8_t data[16] = {0x00}; + // uint8_t datalen = 2; + // uint8_t resplen; + // uint8_t blk1; + // data[0] = 0x08; - // //std read cmd - // if (HF14BCmdRaw(true, true, data, &datalen, false)==0) - // return rawClose(); - - // if (datalen != resplen || !crc) return rawClose(); - //print_ST_Lock_info(data[5]>>2); - return true; -} + // + // if (model == 0x2) { //SR176 has special command: + // data[1] = 0xf; + // resplen = 4; + // } else { + // data[1] = 0xff; + // resplen = 6; + // } -// get and print all info known about any known 14b tag -bool HF14BInfo(bool verbose){ + // //std read cmd + // if (HF14BCmdRaw(true, true, data, &datalen, false)==0) + // return rawClose(); - // try std 14b (atqb) - if (HF14B_Std_Info(verbose)) return true; - - // try ST 14b - if (HF14B_ST_Info(verbose)) return true; - - // try unknown 14b read commands (to be identified later) - // could be read of calypso, CEPAS, moneo, or pico pass. - if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); - return false; + // if (datalen != resplen || !crc) return rawClose(); + //print_ST_Lock_info(data[5]>>2); + return true; } // menu command to get and print all info known about any known 14b tag -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 HF14BInfo(verbose); +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); } -bool HF14B_ST_Reader(bool verbose){ +static bool HF14B_ST_Reader(bool verbose) { - bool isSuccess = false; + bool isSuccess = false; - // SRx get and print general info about SRx chip from UID - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); - return false; + // SRx get and print general info about SRx chip from UID + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + return false; } - - iso14b_card_select_t card; - memcpy(&card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - uint64_t status = resp.arg[0]; + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); - switch( status ){ - case 0: - print_st_general_info(card.uid, card.uidlen); - isSuccess = true; - break; - case 1: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 random chip id fail"); - break; - case 2: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); - break; - case 3: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); - break; - default: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select SRx failed"); - break; - } - return isSuccess; + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 0: + print_st_general_info(card.uid, card.uidlen); + isSuccess = true; + break; + case 1: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 random chip id fail"); + break; + case 2: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); + break; + case 3: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + default: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select SRx failed"); + break; + } + return isSuccess; } -bool HF14B_Std_Reader(bool verbose){ +static bool HF14B_Std_Reader(bool verbose) { - bool isSuccess = false; + bool isSuccess = false; - // 14b get and print UID only (general info) - UsbCommand c = {CMD_ISO_14443B_COMMAND, {ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); - return false; + // 14b get and print UID only (general info) + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + return false; } - - iso14b_card_select_t card; - memcpy(&card, (iso14b_card_select_t *)resp.d.asBytes, sizeof(iso14b_card_select_t)); - - uint64_t status = resp.arg[0]; - - switch( status ){ - case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); - print_atqb_resp(card.atqb, card.cid); - isSuccess = true; - break; - case 2: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); - break; - case 3: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); - break; - default: - if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); - break; - } - return isSuccess; + + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 0: + PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + print_atqb_resp(card.atqb, card.cid); + isSuccess = true; + break; + case 2: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); + break; + case 3: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + default: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); + break; + } + return isSuccess; } // test for other 14b type tags (mimic another reader - don't have tags to identify) -bool HF14B_Other_Reader(){ +static bool HF14B_Other_Reader() { - // uint8_t data[] = {0x00, 0x0b, 0x3f, 0x80}; - // uint8_t datalen = 4; + // uint8_t data[] = {0x00, 0x0b, 0x3f, 0x80}; + // uint8_t datalen = 4; - // // 14b get and print UID only (general info) - // uint32_t flags = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_RAW | ISO14B_APPEND_CRC; - - // UsbCommand c = {CMD_ISO_14443B_COMMAND, {flags, datalen, 0}}; - // memcpy(c.d.asBytes, data, datalen); + // // 14b get and print UID only (general info) + // uint32_t flags = ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_RAW | ISO14B_APPEND_CRC; - // clearCommandBuffer(); - // SendCommand(&c); - // UsbCommand resp; - // WaitForResponse(CMD_ACK,&resp); - - // if (datalen > 2 ) { - // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); - // PrintAndLogEx(NORMAL, "unknown tag type answered to a 0x000b3f80 command ans:"); - // //PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); - // rawclose(); - // return true; - // } + // clearCommandBuffer(); + // SendCommandOLD(CMD_ISO_14443B_COMMAND, flags, datalen, 0, data, datalen); + // PacketResponseNG resp; + // WaitForResponse(CMD_ACK,&resp); - // c.arg1 = 1; - // c.d.asBytes[0] = ISO14443B_AUTHENTICATE; - // clearCommandBuffer(); - // SendCommand(&c); - // UsbCommand resp; - // WaitForResponse(CMD_ACK, &resp); - - // if (datalen > 0) { - // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); - // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0A command ans:"); - // // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); - // rawClose(); - // return true; - // } + // if (datalen > 2 ) { + // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); + // PrintAndLogEx(NORMAL, "unknown tag type answered to a 0x000b3f80 command ans:"); + // //PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); + // rawclose(); + // return true; + // } - // c.arg1 = 1; - // c.d.asBytes[0] = ISO14443B_RESET; - // clearCommandBuffer(); - // SendCommand(&c); - // UsbCommand resp; - // WaitForResponse(CMD_ACK, &resp); + // data[0] = ISO14443B_AUTHENTICATE; + // clearCommandBuffer(); + // SendCommandOLD(CMD_ISO_14443B_COMMAND, flags, 1, 0, data, 1); + // PacketResponseNG resp; + // WaitForResponse(CMD_ACK, &resp); - // if (datalen > 0) { - // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); - // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0C command ans:"); - // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); - // rawClose(); - // return true; - // } - - // rawClose(); - return false; -} + // if (datalen > 0) { + // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); + // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0A command ans:"); + // // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); + // rawClose(); + // return true; + // } -// get and print general info about all known 14b chips -bool HF14BReader(bool verbose){ - - // try std 14b (atqb) - if (HF14B_Std_Reader(verbose)) return true; + // data[0] = ISO14443B_RESET; + // clearCommandBuffer(); + // SendCommandOLD(CMD_ISO_14443B_COMMAND, flags, 1, 0, data, 1); + // PacketResponseNG resp; + // WaitForResponse(CMD_ACK, &resp); - // try ST Microelectronics 14b - if (HF14B_ST_Reader(verbose)) return true; + // if (datalen > 0) { + // PrintAndLogEx(NORMAL, "\n14443-3b tag found:"); + // PrintAndLogEx(NORMAL, "Unknown tag type answered to a 0x0C command ans:"); + // PrintAndLogEx(NORMAL, "%s", sprint_hex(data, datalen)); + // rawClose(); + // return true; + // } - // try unknown 14b read commands (to be identified later) - // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_Other_Reader()) return true; - - if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); - return false; + // rawClose(); + return false; } // menu command to get and print general info about all known 14b chips -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 HF14BReader(verbose); +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); } /* New command to read the contents of a SRI512|SRIX4K tag * SRI* tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory/ */ -int CmdHF14BReadSri(const char *Cmd){ - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_read_srx(); +static int CmdHF14BReadSri(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_read_srx(); - uint8_t tagtype = param_get8(Cmd, 0); - uint8_t blocks = (tagtype == 1) ? 0x7F : 0x0F; - - UsbCommand c = {CMD_READ_SRI_TAG, {blocks, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + uint8_t tagtype = param_get8(Cmd, 0); + uint8_t blocks = (tagtype == 1) ? 0x7F : 0x0F; + + clearCommandBuffer(); + SendCommandMIX(CMD_READ_SRI_TAG, blocks, 0, 0, NULL, 0); + return 0; } // New command to write a SRI512/SRIX4K tag. -int CmdHF14BWriteSri(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 = tolower(param_getchar(Cmd, 0)); - uint8_t blockno = -1; - uint8_t data[4] = {0x00}; - bool isSrix4k = true; - char str[30]; - memset(str, 0x00, sizeof(str)); +static int CmdHF14BWriteSri(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 = tolower(param_getchar(Cmd, 0)); + uint8_t blockno = -1; + uint8_t data[4] = {0x00}; + bool isSrix4k = true; + char str[30]; + memset(str, 0x00, sizeof(str)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_write_srx(); + if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_write_srx(); - if ( cmdp == '2' ) - isSrix4k = false; - - //blockno = param_get8(Cmd, 1); - - if ( param_gethex(Cmd, 1, &blockno, 2) ) { - PrintAndLogEx(WARNING, "block number must include 2 HEX symbols"); - return 0; - } - - if ( isSrix4k ){ - if ( blockno > 0x7f && blockno != 0xff ){ - PrintAndLogEx(FAILED, "block number out of range"); - return 0; - } - } else { - if ( blockno > 0x0f && blockno != 0xff ){ - PrintAndLogEx(FAILED, "block number out of range"); - return 0; - } - } - - if (param_gethex(Cmd, 2, data, 8)) { - PrintAndLogEx(WARNING, "data must include 8 HEX symbols"); - return 0; - } - - if ( blockno == 0xff) { - PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]", - (isSrix4k) ? "SRIX4K":"SRI512", - blockno, - sprint_hex(data,4) - ); - } else { - PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]", - (isSrix4k) ? "SRIX4K":"SRI512", - blockno, - sprint_hex(data,4) - ); - } - - sprintf(str, "-ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); - CmdHF14BCmdRaw(str); - return 0; + if (cmdp == '2') + isSrix4k = false; + + //blockno = param_get8(Cmd, 1); + + if (param_gethex(Cmd, 1, &blockno, 2)) { + PrintAndLogEx(WARNING, "block number must include 2 HEX symbols"); + return 0; + } + + if (isSrix4k) { + if (blockno > 0x7f && blockno != 0xff) { + PrintAndLogEx(FAILED, "block number out of range"); + return 0; + } + } else { + if (blockno > 0x0f && blockno != 0xff) { + PrintAndLogEx(FAILED, "block number out of range"); + return 0; + } + } + + if (param_gethex(Cmd, 2, data, 8)) { + PrintAndLogEx(WARNING, "data must include 8 HEX symbols"); + return 0; + } + + if (blockno == 0xff) { + PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]", + (isSrix4k) ? "SRIX4K" : "SRI512", + blockno, + sprint_hex(data, 4) + ); + } else { + PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]", + (isSrix4k) ? "SRIX4K" : "SRI512", + blockno, + sprint_hex(data, 4) + ); + } + + sprintf(str, "-ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); + CmdHF14BCmdRaw(str); + return 0; } // need to write to file -int CmdHF14BDump(const char*Cmd) { - - uint8_t fileNameLen = 0; - char filename[FILE_PATH_SIZE] = {0}; - char * fptr = filename; - bool errors = false; - uint8_t cmdp = 0, cardtype = 1; - uint16_t cardsize = 0; - uint8_t blocks = 0; - iso14b_card_select_t card; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_14b_dump(); - case 'f': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); - cmdp += 2; - break; - default: - if (cmdp == 0) { - cardtype = param_get8ex(Cmd, cmdp, 1, 10); - cmdp++; - } else { - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - } +static int CmdHF14BDump(const char *Cmd) { - //Validations - if (errors) return usage_hf_14b_dump(); + uint8_t fileNameLen = 0; + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + bool errors = false; + uint8_t cmdp = 0, cardtype = 1; + uint16_t cardsize = 0; + uint8_t blocks = 0; + iso14b_card_select_t card; - switch (cardtype){ - case 2: - cardsize = (512/8) + 4; - blocks = 0x0F; - break; - case 1: - default: - cardsize = (4096/8) + 4; - blocks = 0x7F; - break; - } - - if (!get_14b_UID(&card)) { - PrintAndLogEx(WARNING, "No tag found."); - return 1; - } - - if (fileNameLen < 1) { - PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "hf-14b-"); - FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); - } + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_14b_dump(); + case 'f': + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + cmdp += 2; + break; + default: + if (cmdp == 0) { + cardtype = param_get8ex(Cmd, cmdp, 1, 10); + cmdp++; + } else { + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + } - // detect blocksize from card :) - PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprint_hex(card.uid, card.uidlen)); - - uint8_t data[cardsize]; - memset(data, 0, sizeof(data)); - - int blocknum = 0; - uint8_t *recv = NULL; + //Validations + if (errors) return usage_hf_14b_dump(); - UsbCommand resp; - UsbCommand c = {CMD_ISO_14443B_COMMAND, { ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); + switch (cardtype) { + case 2: + cardsize = (512 / 8) + 4; + blocks = 0x0F; + break; + case 1: + default: + cardsize = (4096 / 8) + 4; + blocks = 0x7F; + break; + } - //select - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - if (resp.arg[0]) { - PrintAndLogEx(INFO, "failed to select %d | %d", resp.arg[0], resp.arg[1]); - goto out; - } - } - - c.arg[0] = ISO14B_APPEND_CRC | ISO14B_RAW; - c.arg[1] = 2; - - uint8_t *req = c.d.asBytes; - req[0] = ISO14443B_READ_BLK; - - for (int retry = 0; retry < 5; retry++) { - - req[1] = blocknum; - - clearCommandBuffer(); - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (!get_14b_UID(&card)) { + PrintAndLogEx(WARNING, "No tag found."); + return 1; + } - uint8_t status = resp.arg[0] & 0xFF; - if ( status > 0 ) { - continue; - } - - uint16_t len = (resp.arg[1] & 0xFFFF); - recv = resp.d.asBytes; - - if ( !check_crc(CRC_14443_B, recv, len) ) { - PrintAndLogEx(FAILED, "crc fail, retrying one more time"); - continue; - } + if (fileNameLen < 1) { + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += sprintf(fptr, "hf-14b-"); + FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); + } - memcpy(data + (blocknum * 4), resp.d.asBytes, 4); + // detect blocksize from card :) + PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprint_hex(card.uid, card.uidlen)); - if ( blocknum == 0xFF) { - //last read. - break; - } - - - retry = 0; - blocknum++; - if ( blocknum > blocks ) { - // read config block - blocknum = 0xFF; - } - - printf("."); fflush(stdout); - } - } - - if ( blocknum != 0xFF) { - PrintAndLogEx(NORMAL, "\n Dump failed"); - goto out; - } - - PrintAndLogEx(NORMAL, "\n"); - PrintAndLogEx(NORMAL, "block# | data | ascii"); - PrintAndLogEx(NORMAL, "---------+--------------+----------"); + uint8_t data[cardsize]; + memset(data, 0, sizeof(data)); - for (int i = 0; i <= blocks; i++) { - PrintAndLogEx(NORMAL, - "%3d/0x%02X | %s | %s", - i, - i, - sprint_hex(data + (i*4), 4 ), - sprint_ascii(data + (i*4), 4) - ); - } - - PrintAndLogEx(NORMAL, "\n"); + int blocknum = 0; + uint8_t *recv = NULL; - - size_t datalen = (blocks+1) * 4; - saveFileEML(filename, "eml", data, datalen, 4); - saveFile(filename, "bin", data, datalen); + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); + + //select + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (resp.oldarg[0]) { + PrintAndLogEx(INFO, "failed to select %d | %d", resp.oldarg[0], resp.oldarg[1]); + goto out; + } + } + + uint8_t req[2] = {ISO14443B_READ_BLK}; + + for (int retry = 0; retry < 5; retry++) { + + req[1] = blocknum; + + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + + uint8_t status = resp.oldarg[0] & 0xFF; + if (status > 0) { + continue; + } + + uint16_t len = (resp.oldarg[1] & 0xFFFF); + recv = resp.data.asBytes; + + if (!check_crc(CRC_14443_B, recv, len)) { + PrintAndLogEx(FAILED, "crc fail, retrying one more time"); + continue; + } + + memcpy(data + (blocknum * 4), resp.data.asBytes, 4); + + if (blocknum == 0xFF) { + //last read. + break; + } + + + retry = 0; + blocknum++; + if (blocknum > blocks) { + // read config block + blocknum = 0xFF; + } + + printf("."); + fflush(stdout); + } + } + + if (blocknum != 0xFF) { + PrintAndLogEx(NORMAL, "\n Dump failed"); + goto out; + } + + PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, "block# | data | ascii"); + PrintAndLogEx(NORMAL, "---------+--------------+----------"); + + for (int i = 0; i <= blocks; i++) { + PrintAndLogEx(NORMAL, + "%3d/0x%02X | %s | %s", + i, + i, + sprint_hex(data + (i * 4), 4), + sprint_ascii(data + (i * 4), 4) + ); + } + + PrintAndLogEx(NORMAL, "\n"); + + + size_t datalen = (blocks + 1) * 4; + saveFileEML(filename, data, datalen, 4); + saveFile(filename, ".bin", data, datalen); out: - return switch_off_field_14b(); + return switch_off_field_14b(); } - -uint32_t srix4kEncode(uint32_t value) { /* -// vv = value -// pp = position -// vv vv vv pp -4 bytes : 00 1A 20 01 -*/ - // only the lower crumbs. - uint8_t block = (value & 0xFF); - uint8_t i = 0; - uint8_t valuebytes[] = {0,0,0}; - - num_to_bytes(value, 3, valuebytes); - - // Scrambled part - // Crumb swapping of value. - uint8_t temp[] = {0,0}; - temp[0] = (CRUMB(value, 22) << 4 | CRUMB(value, 14 ) << 2 | CRUMB(value, 6)) << 4; - temp[0] |= CRUMB(value, 20) << 4 | CRUMB(value, 12 ) << 2 | CRUMB(value, 4); - temp[1] = (CRUMB(value, 18) << 4 | CRUMB(value, 10 ) << 2 | CRUMB(value, 2)) << 4; - temp[1] |= CRUMB(value, 16) << 4 | CRUMB(value, 8 ) << 2 | CRUMB(value, 0); - // chksum part - uint32_t chksum = 0xFF - block; - - // chksum is reduced by each nibbles of value. - for (i = 0; i < 3; ++i){ - chksum -= NIBBLE_HIGH(valuebytes[i]); - chksum -= NIBBLE_LOW(valuebytes[i]); - } +static uint32_t srix4kEncode(uint32_t value) { + // vv = value + // pp = position + // vv vv vv pp + // 4 bytes : 00 1A 20 01 + // only the lower crumbs. + uint8_t block = (value & 0xFF); + uint8_t i = 0; + uint8_t valuebytes[] = {0, 0, 0}; - // base4 conversion and left shift twice - i = 3; - uint8_t base4[] = {0,0,0,0}; - while( chksum !=0 ){ + num_to_bytes(value, 3, valuebytes); + + // Scrambled part + // Crumb swapping of value. + uint8_t temp[] = {0, 0}; + temp[0] = (CRUMB(value, 22) << 4 | CRUMB(value, 14) << 2 | CRUMB(value, 6)) << 4; + temp[0] |= CRUMB(value, 20) << 4 | CRUMB(value, 12) << 2 | CRUMB(value, 4); + temp[1] = (CRUMB(value, 18) << 4 | CRUMB(value, 10) << 2 | CRUMB(value, 2)) << 4; + temp[1] |= CRUMB(value, 16) << 4 | CRUMB(value, 8) << 2 | CRUMB(value, 0); + + // chksum part + uint32_t chksum = 0xFF - block; + + // chksum is reduced by each nibbles of value. + for (i = 0; i < 3; ++i) { + chksum -= NIBBLE_HIGH(valuebytes[i]); + chksum -= NIBBLE_LOW(valuebytes[i]); + } + + // base4 conversion and left shift twice + i = 3; + uint8_t base4[] = {0, 0, 0, 0}; + while (chksum != 0) { base4[i--] = (chksum % 4 << 2); - chksum /= 4; + chksum /= 4; } - - // merge scambled and chksum parts - uint32_t encvalue = - ( NIBBLE_LOW ( base4[0]) << 28 ) | - ( NIBBLE_HIGH( temp[0]) << 24 ) | - - ( NIBBLE_LOW ( base4[1]) << 20 ) | - ( NIBBLE_LOW ( temp[0]) << 16 ) | - - ( NIBBLE_LOW ( base4[2]) << 12 ) | - ( NIBBLE_HIGH( temp[1]) << 8 ) | - - ( NIBBLE_LOW ( base4[3]) << 4 ) | - NIBBLE_LOW ( temp[1] ); - PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue); - return encvalue; -} -uint32_t srix4kDecode(uint32_t value) { - switch(value) { - case 0xC04F42C5: return 0x003139; - case 0xC1484807: return 0x002943; - case 0xC0C60848: return 0x001A20; - } - return 0; -} -uint32_t srix4kDecodeCounter(uint32_t num) { - uint32_t value = ~num; - ++value; - return value; + // merge scambled and chksum parts + uint32_t encvalue = + (NIBBLE_LOW(base4[0]) << 28) | + (NIBBLE_HIGH(temp[0]) << 24) | + + (NIBBLE_LOW(base4[1]) << 20) | + (NIBBLE_LOW(temp[0]) << 16) | + + (NIBBLE_LOW(base4[2]) << 12) | + (NIBBLE_HIGH(temp[1]) << 8) | + + (NIBBLE_LOW(base4[3]) << 4) | + NIBBLE_LOW(temp[1]); + + PrintAndLogEx(NORMAL, "ICE encoded | %08X -> %08X", value, encvalue); + return encvalue; } -uint32_t srix4kGetMagicbytes( uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19 ){ +static uint32_t srix4kDecode(uint32_t value) { + switch (value) { + case 0xC04F42C5: + return 0x003139; + case 0xC1484807: + return 0x002943; + case 0xC0C60848: + return 0x001A20; + } + return 0; +} + +static uint32_t srix4kDecodeCounter(uint32_t num) { + uint32_t value = ~num; + ++value; + return value; +} + +static uint32_t srix4kGetMagicbytes(uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19) { #define MASK 0xFFFFFFFF; - uint32_t uid32 = uid & MASK; - uint32_t counter = srix4kDecodeCounter(block6); - uint32_t decodedBlock18 = srix4kDecode(block18); - uint32_t decodedBlock19 = srix4kDecode(block19); - uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1; + uint32_t uid32 = uid & MASK; + uint32_t counter = srix4kDecodeCounter(block6); + uint32_t decodedBlock18 = srix4kDecode(block18); + uint32_t decodedBlock19 = srix4kDecode(block19); + uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1; - uint32_t result = (uid32 * doubleBlock * counter) & MASK; - PrintAndLogEx(SUCCESS, "Magic bytes | %08X", result); - return result; -} -int srix4kValid(const char *Cmd){ - - uint64_t uid = 0xD00202501A4532F9; - uint32_t block6 = 0xFFFFFFFF; - uint32_t block18 = 0xC04F42C5; - uint32_t block19 = 0xC1484807; - uint32_t block21 = 0xD1BCABA4; - - uint32_t test_b18 = 0x00313918; - uint32_t test_b18_enc = srix4kEncode(test_b18); - //uint32_t test_b18_dec = srix4kDecode(test_b18_enc); - PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc , ""); - - uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19); - PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21); - return 0; + uint32_t result = (uid32 * doubleBlock * counter) & MASK; + PrintAndLogEx(SUCCESS, "Magic bytes | %08X", result); + return result; } -bool waitCmd14b(bool verbose) { +static int srix4kValid(const char *Cmd) { + (void)Cmd; // Cmd is not used so far - bool crc = false; - uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; - uint8_t status = 0; - uint16_t len = 0; - UsbCommand resp; + uint64_t uid = 0xD00202501A4532F9; + uint32_t block6 = 0xFFFFFFFF; + uint32_t block18 = 0xC04F42C5; + uint32_t block19 = 0xC1484807; + uint32_t block21 = 0xD1BCABA4; - if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + uint32_t test_b18 = 0x00313918; + uint32_t test_b18_enc = srix4kEncode(test_b18); + //uint32_t test_b18_dec = srix4kDecode(test_b18_enc); + PrintAndLogEx(SUCCESS, "ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc, ""); - status = (resp.arg[0] & 0xFF); - if ( status > 0 ) return false; - - len = (resp.arg[1] & 0xFFFF); - - memcpy(data, resp.d.asBytes, len); - - if (verbose) { - if ( len >= 3 ) { - crc = check_crc(CRC_14443_B, data, len); - - PrintAndLogEx(NORMAL, "[LEN %u] %s[%02X %02X] %s", - len, - sprint_hex(data, len-2), - data[len-2], - data[len-1], - (crc) ? "OK" : "FAIL" - ); - } else { - PrintAndLogEx(NORMAL, "[LEN %u] %s", len, sprint_hex(data, len) ); - } - } - return true; - } else { - PrintAndLogEx(WARNING, "command execution timeout"); - return false; - } + uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19); + PrintAndLogEx(SUCCESS, "BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21); + return 0; } - +*/ static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"dump", CmdHF14BDump, 0, "Read all memory pages of an ISO14443-B tag, save to file"}, - {"info", CmdHF14Binfo, 0, "Tag information"}, - {"list", CmdHF14BList, 0, "[Deprecated] List ISO 14443B history"}, - {"raw", CmdHF14BCmdRaw, 0, "Send raw hex data to tag"}, - {"reader", CmdHF14BReader, 0, "Act as a 14443B reader to identify a tag"}, - {"sim", CmdHF14BSim, 0, "Fake ISO 14443B tag"}, - {"sniff", CmdHF14BSniff, 0, "Eavesdrop ISO 14443B"}, - {"sriread", CmdHF14BReadSri, 0, "Read contents of a SRI512 | SRIX4K tag"}, - {"sriwrite", CmdHF14BWriteSri, 0, "Write data to a SRI512 | SRIX4K tag"}, - //{"valid", srix4kValid, 1, "srix4k checksum test"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO14443-B tag, save to file"}, + {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, + {"list", CmdHF14BList, AlwaysAvailable, "List ISO 14443B history"}, + {"raw", CmdHF14BCmdRaw, IfPm3Iso14443b, "Send raw hex data to tag"}, + {"reader", CmdHF14BReader, IfPm3Iso14443b, "Act as a 14443B reader to identify a tag"}, + {"sim", CmdHF14BSim, IfPm3Iso14443b, "Fake ISO 14443B tag"}, + {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop ISO 14443B"}, + {"sriread", CmdHF14BReadSri, IfPm3Iso14443b, "Read contents of a SRI512 | SRIX4K tag"}, + {"sriwrite", CmdHF14BWriteSri, IfPm3Iso14443b, "Write data to a SRI512 | SRIX4K tag"}, + //{"valid", srix4kValid, AlwaysAvailable, "srix4k checksum test"}, + {NULL, NULL, NULL, NULL} }; -int CmdHF14B(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +int CmdHF14B(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); } + +// get and print all info known about any known 14b tag +int infoHF14B(bool verbose) { + + // try std 14b (atqb) + if (HF14B_Std_Info(verbose)) 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 (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); + return 0; +} + +// get and print general info about all known 14b chips +int readHF14B(bool verbose) { + + // try std 14b (atqb) + if (HF14B_Std_Reader(verbose)) return 1; + + // try ST Microelectronics 14b + if (HF14B_ST_Reader(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()) return 1; + + if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); + return 0; +} + diff --git a/client/cmdhf14b.h b/client/cmdhf14b.h index 6b44a7304..2180e2088 100644 --- a/client/cmdhf14b.h +++ b/client/cmdhf14b.h @@ -25,35 +25,12 @@ #include "cmdhf14a.h" #include "cmdhf.h" #include "prng.h" -#include "sha1.h" -#include "mifare.h" // structs/enum for ISO14B -#include "protocols.h" // definitions of ISO14B protocol +#include "mbedtls/sha1.h" +#include "mifare.h" // structs/enum for ISO14B +#include "protocols.h" // definitions of ISO14B protocol -int usage_hf_14b_info(void); -int usage_hf_14b_reader(void); -int usage_hf_14b_raw(void); -int usage_hf_14b_sniff(void); -int usage_hf_14b_sim(void); -int usage_hf_14b_read_srx(void); -int usage_hf_14b_write_srx(void); +int CmdHF14B(const char *Cmd); -extern int CmdHF14B(const char *Cmd); -extern int CmdHF14BList(const char *Cmd); -extern int CmdHF14BInfo(const char *Cmd); -extern int CmdHF14BSim(const char *Cmd); -extern int CmdHF14BSniff(const char *Cmd); -extern int CmdHF14BWrite( const char *cmd); -extern int CmdHF14BReader(const char *Cmd); - -extern int CmdHF14BDump(const char *Cmd); - -extern bool HF14BInfo(bool verbose); -extern bool HF14BReader(bool verbose); -extern int CmdHF14BCmdRaw (const char *Cmd); - -// SRi ST Microelectronics read/write -extern int CmdHF14BReadSri(const char *Cmd); -extern int CmdHF14BWriteSri(const char *Cmd); - -bool waitCmd14b(bool verbose); +int infoHF14B(bool verbose); +int readHF14B(bool verbose); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index f54dfe7d8..6f6d1ebc2 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -15,325 +15,339 @@ // Mode 1: // All steps are done on the proxmark, the output of the commands is returned via // USB-debug-print commands. -// Mode 2: +// Mode 2: // The protocol is done on the PC, passing only Iso15693 data frames via USB. This // allows direct communication with a tag on command level // Mode 3: // The proxmark just samples the antenna and passes this "analog" data via USB to // the client. Signal Processing & decoding is done on the pc. This is the slowest -// variant, but offers the possibility to analyze the waveforms directly. +// variant, but offers the possibility to analyze the waveforms directly. #include "cmdhf15.h" -#define FrameSOF Iso15693FrameSOF -#define Logic0 Iso15693Logic0 -#define Logic1 Iso15693Logic1 -#define FrameEOF Iso15693FrameEOF +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF -#define Crc(data, len) crc(CRC_15693, (data), (len)) -#define CheckCrc(data, len) check_crc(CRC_15693, (data), (len)) -#define AddCrc(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +#ifndef Crc15 +# define Crc15(data, len) Crc16ex(CRC_15693, (data), (len)) +#endif +#ifndef CheckCrc15 +# define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) +#endif +#ifndef AddCrc15 +#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +#endif -#define sprintUID(target, uid) Iso15693sprintUID((target), (uid)) - -// structure and database for uid -> tagtype lookups -typedef struct { - uint64_t uid; - int mask; // how many MSB bits used - char* desc; -} productName; +#ifndef sprintUID +# define sprintUID(target, uid) Iso15693sprintUID((target), (uid)) +#endif +// structure and database for uid -> tagtype lookups +typedef struct { + uint64_t uid; + int mask; // how many MSB bits used + const char *desc; +} productName; const productName uidmapping[] = { - // UID, #significant Bits, "Vendor(+Product)" - { 0xE001000000000000LL, 16, "Motorola UK" }, - - // E0 02 xx - // 02 = ST Microelectronics - // XX = IC id (Chip ID Family) - { 0xE002000000000000LL, 16, "ST Microelectronics SA France" }, - { 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"}, - { 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"}, - { 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"}, - { 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"}, + // UID, #significant Bits, "Vendor(+Product)" + { 0xE001000000000000LL, 16, "Motorola UK" }, - { 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" }, - - // E0 04 xx - // 04 = Manufacturer code (Philips/NXP) - // XX = IC id (Chip ID Family) - //I-Code SLI SL2 ICS20 [IC id = 01] - //I-Code SLI-S [IC id = 02] - //I-Code SLI-L [IC id = 03] - //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] - //I-Code SLIX-S [IC id = 02 + bit36 set to 1] - //I-Code SLIX-L [IC id = 03 + bit36 set to 1] - { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, - { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, - { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, - { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, + // E0 02 xx + // 02 = ST Microelectronics + // XX = IC id (Chip ID Family) + { 0xE002000000000000LL, 16, "ST Microelectronics SA France" }, + { 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"}, + { 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"}, + { 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"}, + { 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"}, - // E0 05 XX .. .. .. - // 05 = Manufacturer code (Infineon) - // XX = IC id (Chip ID Family) - { 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" }, - { 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"}, - { 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"}, - { 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"}, - { 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"}, - { 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"}, - { 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"}, - { 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, - { 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, - - { 0xE006000000000000LL, 16, "Cylink USA" }, - - - // E0 07 xx - // 07 = Texas Instruments - // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family) - //Tag IT RFIDType-I Plus, 2kBit, TI Inlay - //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit - //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit - //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit - //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection - { 0xE007000000000000LL, 16, "Texas Instrument France" }, - { 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" }, + { 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" }, - { 0xE008000000000000LL, 16, "Fujitsu Limited Japan" }, - { 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, - { 0xE00A000000000000LL, 16, "NEC Japan" }, - { 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" }, - { 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" }, - { 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" }, - { 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" }, - { 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" }, - { 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" }, - { 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" }, + // E0 04 xx + // 04 = Manufacturer code (Philips/NXP) + // XX = IC id (Chip ID Family) + //I-Code SLI SL2 ICS20 [IC id = 01] + //I-Code SLI-S [IC id = 02] + //I-Code SLI-L [IC id = 03] + //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] + //I-Code SLIX-S [IC id = 02 + bit36 set to 1] + //I-Code SLIX-L [IC id = 03 + bit36 set to 1] + { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, + { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, + { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, + { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, - { 0xE012000000000000LL, 16, "HID Corporation" }, - { 0xE012000000000000LL, 16, "INSIDE Technology France" }, - { 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" }, - { 0xE014000000000000LL, 16, "SHARP Corporation Japan" }, - { 0xE015000000000000LL, 16, "ATMEL France" }, - - { 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)"}, - { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034 [IC id = 01] (Read/Write - no AFI)"}, - { 0xE0160C0000000000LL, 24, "EM-Marin SA (Skidata); EM4035 [IC id = 03] (Read/Write - replaced by 4233)"}, - { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"}, - { 0xE016140000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 05] 28pF"}, - { 0xE016180000000000LL, 24, "EM-Marin SA (Skidata); EM4006 [IC id = 06] (Read Only)"}, - { 0xE0161C0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 07] 23,5pF (Read/Write)"}, - { 0xE016200000000000LL, 24, "EM-Marin SA (Skidata); EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"}, - { 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"}, - { 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" }, - { 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"}, - { 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"}, - { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "}, - { 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" }, - { 0xE016A80000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 42] 97pF" }, - { 0xE016BC0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 47] 97pF" }, + // E0 05 XX .. .. .. + // 05 = Manufacturer code (Infineon) + // XX = IC id (Chip ID Family) + { 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" }, + { 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"}, + { 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"}, + { 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"}, + { 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"}, + { 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"}, + { 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"}, + { 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, + { 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, - { 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" }, - { 0xE018000000000000LL, 16, "ZMD AG Germany" }, - { 0xE019000000000000LL, 16, "XICOR, Inc. USA" }, - { 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" }, - { 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, - { 0xE01C000000000000LL, 16, "Emosyn USA" }, - { 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, - { 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" }, - { 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" }, - { 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" }, - { 0xE021000000000000LL, 16, "TAGSYS France" }, - { 0xE022000000000000LL, 16, "Transcore USA" }, - { 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" }, - { 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" }, - { 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" }, - { 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" }, - { 0xE027000000000000LL, 16, "Cypak AB Sweden" }, - { 0xE028000000000000LL, 16, "Ricoh Japan" }, - { 0xE029000000000000LL, 16, "ASK France" }, - { 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" }, - { 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" }, - { 0xE02C000000000000LL, 16, "Impinj, Inc. USA" }, - { 0xE02D000000000000LL, 16, "RightPlug Alliance USA" }, - { 0xE02E000000000000LL, 16, "Broadcom Corporation USA" }, - { 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" }, - { 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" }, - { 0xE031000000000000LL, 16, "RFIDsec Denmark" }, - { 0xE032000000000000LL, 16, "Schweizer Electronic AG Germany" }, - { 0xE033000000000000LL, 16, "AMIC Technology Corp Taiwan" }, - { 0xE034000000000000LL, 16, "Mikron JSC Russia" }, - { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" }, - { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" }, - { 0xE037000000000000LL, 16, "Kovio USA" }, - { 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, - { 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" }, - { 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" }, - { 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" }, - { 0xE03C000000000000LL, 16, "Verayo Inc. USA" }, - { 0xE03D000000000000LL, 16, "HID Global USA" }, - { 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" }, - { 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" }, - { 0xE040000000000000LL, 16, "Gemalto SA France" }, - { 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" }, - { 0xE042000000000000LL, 16, "3Alogics Inc Korea" }, - { 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" }, - { 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" }, - { 0,0,"no tag-info available" } // must be the last entry + { 0xE006000000000000LL, 16, "Cylink USA" }, + + + // E0 07 xx + // 07 = Texas Instruments + // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family) + //Tag IT RFIDType-I Plus, 2kBit, TI Inlay + //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit + //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit + //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit + //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection + { 0xE007000000000000LL, 16, "Texas Instrument France" }, + { 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 Limited Japan" }, + { 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, + { 0xE00A000000000000LL, 16, "NEC Japan" }, + { 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" }, + { 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" }, + { 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" }, + { 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" }, + { 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" }, + { 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" }, + { 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" }, + + { 0xE012000000000000LL, 16, "HID Corporation" }, + { 0xE012000000000000LL, 16, "INSIDE Technology France" }, + { 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" }, + { 0xE014000000000000LL, 16, "SHARP Corporation Japan" }, + { 0xE015000000000000LL, 16, "ATMEL France" }, + + { 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)"}, + { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034 [IC id = 01] (Read/Write - no AFI)"}, + { 0xE0160C0000000000LL, 24, "EM-Marin SA (Skidata); EM4035 [IC id = 03] (Read/Write - replaced by 4233)"}, + { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"}, + { 0xE016140000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 05] 28pF"}, + { 0xE016180000000000LL, 24, "EM-Marin SA (Skidata); EM4006 [IC id = 06] (Read Only)"}, + { 0xE0161C0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 07] 23,5pF (Read/Write)"}, + { 0xE016200000000000LL, 24, "EM-Marin SA (Skidata); EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"}, + { 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"}, + { 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" }, + { 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"}, + { 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"}, + { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "}, + { 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" }, + { 0xE016A80000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 42] 97pF" }, + { 0xE016BC0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 47] 97pF" }, + + { 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" }, + { 0xE018000000000000LL, 16, "ZMD AG Germany" }, + { 0xE019000000000000LL, 16, "XICOR, Inc. USA" }, + { 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" }, + { 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, + { 0xE01C000000000000LL, 16, "Emosyn USA" }, + { 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, + { 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" }, + { 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" }, + { 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" }, + { 0xE021000000000000LL, 16, "TAGSYS France" }, + { 0xE022000000000000LL, 16, "Transcore USA" }, + { 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" }, + { 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" }, + { 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" }, + { 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" }, + { 0xE027000000000000LL, 16, "Cypak AB Sweden" }, + { 0xE028000000000000LL, 16, "Ricoh Japan" }, + { 0xE029000000000000LL, 16, "ASK France" }, + { 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" }, + { 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" }, + { 0xE02C000000000000LL, 16, "Impinj, Inc. USA" }, + { 0xE02D000000000000LL, 16, "RightPlug Alliance USA" }, + { 0xE02E000000000000LL, 16, "Broadcom Corporation USA" }, + { 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" }, + { 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" }, + { 0xE031000000000000LL, 16, "RFIDsec Denmark" }, + { 0xE032000000000000LL, 16, "Schweizer Electronic AG Germany" }, + { 0xE033000000000000LL, 16, "AMIC Technology Corp Taiwan" }, + { 0xE034000000000000LL, 16, "Mikron JSC Russia" }, + { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" }, + { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" }, + { 0xE037000000000000LL, 16, "Kovio USA" }, + { 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, + { 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" }, + { 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" }, + { 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" }, + { 0xE03C000000000000LL, 16, "Verayo Inc. USA" }, + { 0xE03D000000000000LL, 16, "HID Global USA" }, + { 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" }, + { 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" }, + { 0xE040000000000000LL, 16, "Gemalto SA France" }, + { 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" }, + { 0xE042000000000000LL, 16, "3Alogics Inc Korea" }, + { 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" }, + { 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" }, + { 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 +// *buf should be large enough to fit the 64bit uid // returns 1 if suceeded -int getUID(uint8_t *buf) { +static int getUID(uint8_t *buf) { - UsbCommand resp; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? + PacketResponseNG resp; + uint8_t data[5]; + 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 - c.d.asBytes[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - c.d.asBytes[1] = ISO15_CMD_INVENTORY; - c.d.asBytes[2] = 0; // mask length + AddCrc15(data, 3); - AddCrc(c.d.asBytes, 3); - c.arg[0] = 5; // len + uint8_t retry; - uint8_t retry; - - // don't give up the at the first try - for (retry = 0; retry < 3; retry++) { + // don't give up the at the first try + for (retry = 0; retry < 3; retry++) { - clearCommandBuffer(); - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - - uint8_t resplen = resp.arg[0]; - if (resplen >= 12 && CheckCrc(resp.d.asBytes, 12)) { - memcpy(buf, resp.d.asBytes + 2, 8); - return 1; - } - } - } // retry - - if ( retry >= 3 ) - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - - return 0; + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, sizeof(data), 1, 1, data, sizeof(data)); + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + + uint8_t resplen = resp.oldarg[0]; + if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) { + memcpy(buf, resp.data.asBytes + 2, 8); + return 1; + } + } + } // retry + + return 0; } // get a product description based on the UID -// uid[8] tag uid -// returns description of the best match -static char* getTagInfo_15(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++; - } +// uid[8] tag uid +// returns description of the best match +static const char *getTagInfo_15(uint8_t *uid) { + uint64_t myuid, mask; + int i = 0, best = -1; + memcpy(&myuid, uid, sizeof(uint64_t)); + while (uidmapping[i].mask > 0) { + mask = (~0ULL) << (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; + if (best >= 0) + return uidmapping[best].desc; + return uidmapping[i].desc; } // return a clear-text message to an errorcode -static char* TagErrorStr(uint8_t error) { - switch (error) { - case 0x01: return "The command is not supported"; - 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 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."; - case 0x14: return "The specified block was not successfully locked."; - default: return "Reserved for Future Use or Custom command error."; - } +static const char *TagErrorStr(uint8_t error) { + switch (error) { + case 0x01: + return "The command is not supported"; + 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 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."; + case 0x14: + return "The specified block was not successfully locked."; + default: + return "Reserved for Future Use or Custom command error."; + } } -int usage_15_demod(void){ - PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n" - "Gather samples with 'hf 15 read' / 'hf 15 record'"); - return 0; +static int CmdHF15Help(const char *Cmd); + +static int usage_15_demod(void) { + PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n" + "Gather samples with 'hf 15 read' / 'hf 15 record'"); + return 0; } -int usage_15_samples(void){ - PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n" - "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal"); - return 0; +static int usage_15_samples(void) { + PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n" + "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal"); + return 0; } -int usage_15_info(void){ - PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n" - "command may fail, depending on tag.\n" - "defaults to '1 out of 4' mode\n" - "\n" - "Usage: hf 15 info [options] \n" - "Options:\n" - "\t-2 use slower '1 out of 256' mode\n" - "\tuid (either): \n" - "\t <8B hex> full UID eg E011223344556677\n" - "\t u unaddressed mode\n" - "\t * scan for tag\n" - "Examples:\n" - "\thf 15 info u"); - return 0; +static int usage_15_info(void) { + PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n" + "command may fail, depending on tag.\n" + "defaults to '1 out of 4' mode\n" + "\n" + "Usage: hf 15 info [options] \n" + "Options:\n" + "\t-2 use slower '1 out of 256' mode\n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "Examples:\n" + "\thf 15 info u"); + return 0; } -int usage_15_record(void){ - PrintAndLogEx(NORMAL, "Record activity without enableing carrier"); - return 0; +static int usage_15_record(void) { + PrintAndLogEx(NORMAL, "Record activity without enableing carrier"); + return 0; } -int usage_15_reader(void){ - PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n" - "\n" - "Usage: hf 15 reader [h]\n" - "Options:\n" - "\th this help\n" - "\n" - "Example:\n" - "\thf 15 reader"); - return 0; +static int usage_15_reader(void) { + PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n" + "\n" + "Usage: hf 15 reader [h]\n" + "Options:\n" + "\th this help\n" + "\n" + "Example:\n" + "\thf 15 reader"); + return 0; } -int usage_15_sim(void){ - PrintAndLogEx(NORMAL, "Usage: hf 15 sim \n" - "\n" - "Example:\n" - "\thf 15 sim E016240000000000"); - return 0; +static int usage_15_sim(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 sim \n" + "\n" + "Example:\n" + "\thf 15 sim E016240000000000"); + return 0; } -int usage_15_findafi(void){ - PrintAndLogEx(NORMAL, "'hf 15 finafi' This command needs a helptext. Feel free to add one!"); - return 0; +static int usage_15_findafi(void) { + PrintAndLogEx(NORMAL, "'hf 15 finafi' This command needs a helptext. Feel free to add one!"); + return 0; } -int usage_15_dump(void){ - PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n" - "\n" - "Usage: hf 15 dump [h] \n" - "Options:\n" - "\th this help\n" - "\tf filename, if no UID will be used as filename\n" - "\n" - "Example:\n" - "\thf 15 dump f\n" - "\thf 15 dump f mydump"); - return 0; +static int usage_15_dump(void) { + PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n" + "\n" + "Usage: hf 15 dump [h] \n" + "Options:\n" + "\th this help\n" + "\tf filename, if no UID will be used as filename\n" + "\n" + "Example:\n" + "\thf 15 dump f\n" + "\thf 15 dump f mydump"); + return 0; } -int usage_15_restore(void){ - char *options[][2]={ +static int usage_15_restore(void) { + const char *options[][2] = { {"h", "this help"}, {"-2", "use slower '1 out of 256' mode"}, {"-o", "set OPTION Flag (needed for TI)"}, @@ -346,8 +360,8 @@ int usage_15_restore(void){ PrintAndLogOptions(options, 7, 3); return 0; } -int usage_15_raw(void){ - char *options[][2]={ +static int usage_15_raw(void) { + const char *options[][2] = { {"-r", "do not read response" }, {"-2", "use slower '1 out of 256' mode" }, {"-c", "calculate and append CRC" }, @@ -357,949 +371,943 @@ int usage_15_raw(void){ PrintAndLogOptions(options, 4, 3); return 0; } -int usage_15_read(void){ - PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] \n" - "Options:\n" - "\t-2 use slower '1 out of 256' mode\n" - "\tuid (either): \n" - "\t <8B hex> full UID eg E011223344556677\n" - "\t u unaddressed mode\n" - "\t * scan for tag\n" - "\tpage#: page number 0-255"); - return 0; +static int usage_15_read(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] \n" + "Options:\n" + "\t-2 use slower '1 out of 256' mode\n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tpage#: page number 0-255"); + return 0; } -int usage_15_write(void){ - PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] \n" - "Options:\n" - "\t-2 use slower '1 out of 256' mode\n" - "\t-o set OPTION Flag (needed for TI)\n" - "\tuid (either): \n" - "\t <8B hex> full UID eg E011223344556677\n" - "\t u unaddressed mode\n" - "\t * scan for tag\n" - "\tpage#: page number 0-255\n" - "\thexdata: data to be written eg AA BB CC DD"); - return 0; +static int usage_15_write(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] \n" + "Options:\n" + "\t-2 use slower '1 out of 256' mode\n" + "\t-o set OPTION Flag (needed for TI)\n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tpage#: page number 0-255\n" + "\thexdata: data to be written eg AA BB CC DD"); + return 0; } -int usage_15_readmulti(void){ - PrintAndLogEx(NORMAL, "Usage: hf 15 readmulti [options] \n" - "Options:\n" - "\t-2 use slower '1 out of 256' mode\n" - "\tuid (either): \n" - "\t <8B hex> full UID eg E011223344556677\n" - "\t u unaddressed mode\n" - "\t * scan for tag\n" - "\tstart#: page number to start 0-255\n" - "\tcount#: number of pages"); - return 0; +static int usage_15_readmulti(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 readmulti [options] \n" + "Options:\n" + "\t-2 use slower '1 out of 256' mode\n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tstart#: page number to start 0-255\n" + "\tcount#: number of pages"); + return 0; } + +/** + * parses common HF 15 CMD parameters and prepares some data structures + * Parameters: + * **cmd command line + */ +static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 + int temp; + uint8_t uid[8] = {0x00}; + uint32_t tmpreqlen = 0; + + // strip + while (**cmd == ' ' || **cmd == '\t')(*cmd)++; + + if (strstr(*cmd, "-2") == *cmd) { + *arg1 = 0; // use 1of256 + (*cmd) += 2; + } + + // strip + while (**cmd == ' ' || **cmd == '\t')(*cmd)++; + + if (strstr(*cmd, "-o") == *cmd) { + req[tmpreqlen] = ISO15_REQ_OPTION; + (*cmd) += 2; + } + + // strip + while (**cmd == ' ' || **cmd == '\t')(*cmd)++; + + switch (**cmd) { + case 0: + PrintAndLogEx(WARNING, "missing addr"); + return 0; + break; + case 'u': + case 'U': + // unaddressed mode may not be supported by all vendors + req[tmpreqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY; + req[tmpreqlen++] = iso15cmd; + break; + case '*': + // we scan for the UID ourself + req[tmpreqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[tmpreqlen++] = iso15cmd; + + if (!getUID(uid)) { + PrintAndLogEx(WARNING, "No tag found"); + return 0; + } + memcpy(&req[tmpreqlen], uid, sizeof(uid)); + PrintAndLogEx(NORMAL, "Detected UID %s", sprintUID(NULL, uid)); + tmpreqlen += sizeof(uid); + break; + default: + req[tmpreqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[tmpreqlen++] = iso15cmd; + + // parse UID + for (int i = 0; i < 8 && (*cmd)[i * 2] && (*cmd)[i * 2 + 1]; i++) { + sscanf((char[]) {(*cmd)[i * 2], (*cmd)[i * 2 + 1], 0}, "%X", &temp); + uid[7 - i] = temp & 0xff; + } + + PrintAndLogEx(NORMAL, "Using UID %s", sprintUID(NULL, uid)); + memcpy(&req[tmpreqlen], uid, sizeof(uid)); + tmpreqlen += sizeof(uid); + break; + } + // skip to next space + while (**cmd != ' ' && **cmd != '\t')(*cmd)++; + // skip over the space + while (**cmd == ' ' || **cmd == '\t')(*cmd)++; + + *reqlen = tmpreqlen; + return 1; +} + // Mode 3 //helptext -int CmdHF15Demod(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_demod(); - - // The sampling rate is 106.353 ksps/s, for T = 18.8 us - int i, j; - int max = 0, maxPos = 0; - int skip = 4; +static int CmdHF15Demod(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_demod(); - if (GraphTraceLen < 1000) return 0; + // The sampling rate is 106.353 ksps/s, for T = 18.8 us + int i, j; + int max = 0, maxPos = 0; + int skip = 4; - // First, correlate for SOF - for (i = 0; i < 1000; i++) { - int corr = 0; - for (j = 0; j < ARRAYLEN(FrameSOF); j += skip) { - corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; - } - if (corr > max) { - max = corr; - maxPos = i; - } - } + if (GraphTraceLen < 1000) return 0; - PrintAndLogEx(NORMAL, "SOF at %d, correlation %d", maxPos, max / (ARRAYLEN(FrameSOF) / 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, 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) { - PrintAndLogEx(NORMAL, "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)) >= GraphTraceLen) { - PrintAndLogEx(NORMAL, "ran off end!"); - break; - } - } - - if (mask != 0x01) { - PrintAndLogEx(WARNING, "Error, uneven octet! (discard extra bits!)"); - PrintAndLogEx(NORMAL, " mask = %02x", mask); - } - PrintAndLogEx(NORMAL, "%d octets", k); - - for (i = 0; i < k; i++) - PrintAndLogEx(NORMAL, "# %2d: %02x ", i, outBuf[i]); + // First, correlate for SOF + for (i = 0; i < 1000; i++) { + int corr = 0; + for (j = 0; j < ARRAYLEN(FrameSOF); j += skip) { + corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; + } + if (corr > max) { + max = corr; + maxPos = i; + } + } - PrintAndLogEx(NORMAL, "CRC %04x", Crc(outBuf, k - 2)); - return 0; + PrintAndLogEx(NORMAL, "SOF at %d, correlation %d", maxPos, max / (ARRAYLEN(FrameSOF) / 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, 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) { + PrintAndLogEx(NORMAL, "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)) >= GraphTraceLen) { + PrintAndLogEx(NORMAL, "ran off end!"); + break; + } + } + + if (mask != 0x01) { + PrintAndLogEx(WARNING, "Error, uneven octet! (discard extra bits!)"); + PrintAndLogEx(NORMAL, " mask = %02x", mask); + } + PrintAndLogEx(NORMAL, "%d octets", k); + + for (i = 0; i < k; i++) + PrintAndLogEx(NORMAL, "# %2d: %02x ", i, outBuf[i]); + + PrintAndLogEx(NORMAL, "CRC %04x", Crc15(outBuf, k - 2)); + return 0; } // * Acquire Samples as Reader (enables carrier, sends inquiry) //helptext -int CmdHF15Samples(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_samples(); +static int CmdHF15Samples(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_samples(); - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - - //download samples - getSamples(0, false); - return 0; + clearCommandBuffer(); + SendCommandNG(CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693, NULL, 0); + + getSamples(0, false); + return 0; } /** * Commandline handling: HF15 CMD SYSINFO * get system information from tag/VICC */ -int CmdHF15Info(const char *Cmd) { +static int CmdHF15Info(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd)<1 || cmdp == 'h' || cmdp == 'H') return usage_15_info(); + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_info(); - UsbCommand resp; - uint8_t *recv; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - uint8_t *req = c.d.asBytes; - char cmdbuf[100]; - char *cmd = cmdbuf; - memset(cmdbuf, 0, sizeof(cmdbuf)); - - strncpy(cmd, Cmd, 99); - - if ( !prepareHF15Cmd(&cmd, &c, ISO15_CMD_SYSINFO) ) - return 0; + PacketResponseNG resp; + uint8_t *recv; + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen; + uint8_t arg1 = 1; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; - AddCrc(req, c.arg[0]); - c.arg[0] += 2; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); - //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(c.d.asBytes, reqlen) ); - - clearCommandBuffer(); - SendCommand(&c); + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_SYSINFO)) + return 0; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; - } - - uint32_t status = resp.arg[0]; - - if ( status < 2 ) { - PrintAndLogEx(NORMAL, "iso15693 card doesn't answer to systeminfo command"); - return 1; - } - - recv = resp.d.asBytes; - - if ( recv[0] & ISO15_RES_ERROR ) { - PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; - } - - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, recv+2)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(recv+2)); - PrintAndLogEx(NORMAL, " SYSINFO : %s", sprint_hex(recv, status-2)); + AddCrc15(req, reqlen); + reqlen += 2; - // DSFID - if (recv[1] & 0x01) - PrintAndLogEx(NORMAL, " - DSFID supported [0x%02X]", recv[10]); - else - PrintAndLogEx(NORMAL, " - DSFID not supported"); - - // AFI - if (recv[1] & 0x02) - PrintAndLogEx(NORMAL, " - AFI supported [0x%02X]", recv[11]); - else - PrintAndLogEx(NORMAL, " - AFI not supported"); + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); - // IC reference - if (recv[1] & 0x08) - PrintAndLogEx(NORMAL, " - IC reference supported [0x%02X]", recv[14]); - else - PrintAndLogEx(NORMAL, " - IC reference not supported"); + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, reqlen, arg1, 1, req, reqlen); - // memory - if (recv[1] & 0x04) { - PrintAndLogEx(NORMAL, " - Tag provides info on memory layout (vendor dependent)"); - uint8_t blocks = recv[12]+1; - uint8_t size = (recv[13] & 0x1F); - PrintAndLogEx(NORMAL, " %u (or %u) bytes/blocks x %u blocks", size+1, size, blocks ); - } else { - PrintAndLogEx(NORMAL, " - Tag does not provide information on memory layout"); - } - PrintAndLogEx(NORMAL, "\n"); - return 0; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "iso15693 card select failed"); + return 1; + } + + uint32_t status = resp.oldarg[0]; + + if (status < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command"); + return 1; + } + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(WARNING, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return 3; + } + + PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, recv + 2)); + PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(recv + 2)); + PrintAndLogEx(NORMAL, " SYSINFO : %s", sprint_hex(recv, status - 2)); + + // DSFID + if (recv[1] & 0x01) + PrintAndLogEx(NORMAL, " - DSFID supported [0x%02X]", recv[10]); + else + PrintAndLogEx(NORMAL, " - DSFID not supported"); + + // AFI + if (recv[1] & 0x02) + PrintAndLogEx(NORMAL, " - AFI supported [0x%02X]", recv[11]); + else + PrintAndLogEx(NORMAL, " - AFI not supported"); + + // IC reference + if (recv[1] & 0x08) + PrintAndLogEx(NORMAL, " - IC reference supported [0x%02X]", recv[14]); + else + PrintAndLogEx(NORMAL, " - IC reference not supported"); + + // memory + if (recv[1] & 0x04) { + PrintAndLogEx(NORMAL, " - Tag provides info on memory layout (vendor dependent)"); + uint8_t blocks = recv[12] + 1; + uint8_t size = (recv[13] & 0x1F); + PrintAndLogEx(NORMAL, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); + } else { + PrintAndLogEx(NORMAL, " - Tag does not provide information on memory layout"); + } + PrintAndLogEx(NORMAL, "\n"); + return 0; } // Record Activity without enabeling carrier //helptext -int CmdHF15Record(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_record(); - - UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; +static int CmdHF15Record(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_record(); + + clearCommandBuffer(); + SendCommandNG(CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693, NULL, 0); + return 0; } -// used with 'hf search' -int HF15Reader(const char *Cmd, bool verbose) { - uint8_t uid[8] = {0,0,0,0,0,0,0,0}; - if (!getUID(uid)) { - if (verbose) PrintAndLogEx(WARNING, "No tag found."); - return 0; - } +static int CmdHF15Reader(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_reader(); - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, uid)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(uid)); - return 1; -} - -int CmdHF15Reader(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_reader(); - - HF15Reader(Cmd, true); - return 0; + readHF15Uid(true); + return 0; } // Simulation is still not working very good // helptext -int CmdHF15Sim(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_sim(); +static int CmdHF15Sim(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim(); - uint8_t uid[8] = {0,0,0,0,0,0,0,0}; - if (param_gethex(Cmd, 0, uid, 16)) { - PrintAndLogEx(NORMAL, "UID must include 16 HEX symbols"); - return 0; - } - - PrintAndLogEx(NORMAL, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)) ); + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + if (param_gethex(Cmd, 0, uid, 16)) { + PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); + return 0; + } - UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; - memcpy(c.d.asBytes, uid, 8); - clearCommandBuffer(); - SendCommand(&c); - return 0; + PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid))); + + clearCommandBuffer(); + SendCommandOLD(CMD_SIMTAG_ISO_15693, 0, 0, 0, uid, 8); + 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) // helptext -int CmdHF15Afi(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') return usage_15_findafi(); +static int CmdHF15Afi(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_15_findafi(); - PrintAndLogEx(NORMAL, "press pm3-button to cancel"); - - UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); + + clearCommandBuffer(); + SendCommandMIX(CMD_ISO_15693_FIND_AFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); + return 0; } typedef struct { - uint8_t lock; - uint8_t block[4]; + uint8_t lock; + uint8_t block[4]; } t15memory; // Reads all memory pages // need to write to file -int CmdHF15Dump(const char*Cmd) { - - uint8_t fileNameLen = 0; - char filename[FILE_PATH_SIZE] = {0}; - char * fptr = filename; - bool errors = false; - uint8_t cmdp = 0; - uint8_t uid[8] = {0,0,0,0,0,0,0,0}; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_15_dump(); - case 'f': - fileNameLen = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } +static int CmdHF15Dump(const char *Cmd) { - //Validations - if (errors) return usage_15_dump(); - - if (fileNameLen < 1) { + uint8_t fileNameLen = 0; + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + bool errors = false; + uint8_t cmdp = 0; + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - PrintAndLogEx(INFO, "Using UID as filename"); + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_15_dump(); + case 'f': + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } - if (!getUID(uid)) { - PrintAndLogEx(WARNING, "No tag found."); - return 1; - } - - fptr += sprintf(fptr, "hf-15-"); - FillFileNameByUID(fptr,uid,"-dump",sizeof(uid)); + //Validations + if (errors) return usage_15_dump(); - } - // detect blocksize from card :) - - PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprintUID(NULL, uid)); + if (!getUID(uid)) { + PrintAndLogEx(WARNING, "No tag found."); + return 1; + } - int blocknum = 0; - uint8_t *recv = NULL; + if (fileNameLen < 1) { - // memory. - t15memory mem[256]; - - uint8_t data[256*4] = {0}; - memset(data, 0, sizeof(data)); + PrintAndLogEx(INFO, "Using UID as filename"); - UsbCommand resp; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - uint8_t *req = c.d.asBytes; - req[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[1] = ISO15_CMD_READ; + fptr += sprintf(fptr, "hf-15-"); + FillFileNameByUID(fptr, uid, "-dump", sizeof(uid)); + } + // detect blocksize from card :) - // copy uid to read command - memcpy(req+2, uid, sizeof(uid)); - - for (int retry = 0; retry < 5; retry++) { - - req[10] = blocknum; - AddCrc(req, 11); - c.arg[0] = 13; - - clearCommandBuffer(); - SendCommand(&c); - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); - uint8_t len = resp.arg[0]; - if ( len < 2 ) { - PrintAndLogEx(FAILED, "iso15693 card select failed"); - continue; - } - - recv = resp.d.asBytes; - - if ( !CheckCrc(recv, len) ) { - PrintAndLogEx(FAILED, "crc fail"); - continue; - } + int blocknum = 0; + uint8_t *recv = NULL; - if (recv[0] & ISO15_RES_ERROR) { - PrintAndLogEx(FAILED, "Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1]) ); - break; - } - - mem[blocknum].lock = resp.d.asBytes[0]; - memcpy(mem[blocknum].block, resp.d.asBytes + 1, 4); - memcpy(data + (blocknum * 4), resp.d.asBytes + 1, 4); - - retry = 0; - blocknum++; - - printf("."); fflush(stdout); - } - } - PrintAndLogEx(NORMAL, "\n"); + // memory. + t15memory mem[256]; - PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); - PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); - for (int i = 0; i < blocknum; i++) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", i, i, sprint_hex(mem[i].block, 4 ), mem[i].lock, sprint_ascii(mem[i].block, 4) ); - } - PrintAndLogEx(NORMAL, "\n"); + uint8_t data[256 * 4] = {0}; + memset(data, 0, sizeof(data)); - size_t datalen = blocknum * 4; - saveFileEML(filename, "eml", data, datalen, 4); - saveFile(filename, "bin", data, datalen); - return 0; + PacketResponseNG resp; + uint8_t req[13]; + req[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[1] = ISO15_CMD_READ; + + // copy uid to read command + memcpy(req + 2, uid, sizeof(uid)); + + for (int retry = 0; retry < 5; retry++) { + + req[10] = blocknum; + AddCrc15(req, 11); + + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, sizeof(req), 1, 1, req, sizeof(req)); + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + + uint8_t len = resp.oldarg[0]; + if (len < 2) { + PrintAndLogEx(FAILED, "iso15693 card select failed"); + continue; + } + + recv = resp.data.asBytes; + + if (!CheckCrc15(recv, len)) { + PrintAndLogEx(FAILED, "crc fail"); + continue; + } + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(FAILED, "Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1])); + break; + } + + mem[blocknum].lock = resp.data.asBytes[0]; + memcpy(mem[blocknum].block, resp.data.asBytes + 1, 4); + memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4); + + retry = 0; + blocknum++; + + printf("."); + fflush(stdout); + } + } + PrintAndLogEx(NORMAL, "\n"); + + PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); + PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); + for (int i = 0; i < blocknum; i++) { + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", i, i, sprint_hex(mem[i].block, 4), mem[i].lock, sprint_ascii(mem[i].block, 4)); + } + PrintAndLogEx(NORMAL, "\n"); + + size_t datalen = blocknum * 4; + saveFileEML(filename, data, datalen, 4); + saveFile(filename, ".bin", data, datalen); + return 0; } -int CmdHF15Restore(const char*Cmd) { - FILE *file; - - uint8_t uid[8]={0x00}; - char filename[FILE_PATH_SIZE] = {0x00}; - char buff[255] = {0x00}; - size_t blocksize=4; - uint8_t cmdp = 0; - char newCmdPrefix[255] = {0x00}, tmpCmd[255] = {0x00}; - char param[FILE_PATH_SIZE]=""; - char hex[255]=""; - uint8_t retries = 3, tried = 0; - int retval=0; - size_t bytes_read; - uint8_t i=0; - while(param_getchar(Cmd, cmdp) != 0x00) { - switch(tolower(param_getchar(Cmd, cmdp))) { - case '-': - param_getstr(Cmd, cmdp, param, sizeof(param)); - switch(param[1]) - { - case '2': - case 'o': strncpy(newCmdPrefix, " ",sizeof(newCmdPrefix)-1); - strncat(newCmdPrefix, param, sizeof(newCmdPrefix)-1); - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%s'", param); - return usage_15_restore(); - } - break; - case 'f': - param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); - cmdp++; - break; - case 'r': - retries=param_get8ex(Cmd, cmdp+1, 3, 10); - cmdp++; - break; - case 'b': - blocksize=param_get8ex(Cmd, cmdp+1, 4, 10); - cmdp++; - break; - case 'u': - param_getstr(Cmd, cmdp+1, buff, FILE_PATH_SIZE); - cmdp++; - snprintf(filename,sizeof(filename),"hf-15-dump-%s-bin",buff); - break; - case 'h': - return usage_15_restore(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - return usage_15_restore(); - break; - } - cmdp++; - } - PrintAndLogEx(INFO,"Blocksize: %u",blocksize); - if(filename[0]=='\0') - { - PrintAndLogEx(WARNING,"Please provide a filename"); - return 1; - } - - if ((file = fopen(filename,"rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file %s", filename); - return 2; - } - - if (!getUID(uid)) { - PrintAndLogEx(WARNING, "No tag found"); - return 3; - } - while (1) { - tried=0; - hex[0]=0x00; - tmpCmd[0]=0x00; - - bytes_read = fread( buff, 1, blocksize, file ); - if ( bytes_read == 0) { - PrintAndLogEx(SUCCESS, "File reading done (%s).", filename); - fclose(file); - return 0; - } - else if ( bytes_read != blocksize) { - PrintAndLogEx(WARNING, "File reading error (%s), %u bytes read instead of %u bytes.", filename, bytes_read, blocksize); - fclose(file); - return 2; - } - for(int j=0;j= retries) - return retval; - i++; - } - fclose(file); +static int CmdHF15List(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + //PrintAndLogEx(WARNING, "Deprecated command, use 'hf list 15' instead"); + CmdTraceList("15"); + return 0; } -int CmdHF15List(const char *Cmd) { - //PrintAndLogEx(WARNING, "Deprecated command, use 'hf list 15' instead"); - CmdTraceList("15"); - return 0; -} +static int CmdHF15Raw(const char *Cmd) { -int CmdHF15Raw(const char *Cmd) { + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_raw(); - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd)<3 || cmdp == 'h' || cmdp == 'H') return usage_15_raw(); + PacketResponseNG resp; + int reply = 1, fast = 1, i = 0; + bool crc = false; + char buf[5] = ""; + uint8_t data[100]; + uint32_t datalen = 0, temp; - UsbCommand resp; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - int reply = 1, fast = 1, i = 0; - bool crc = false; - char buf[5] = ""; - uint8_t data[100]; - uint32_t datalen = 0, temp; - - // 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 '2': - fast = 0; - break; - case 'c': - case 'C': - crc = true; - break; - default: - PrintAndLogEx(WARNING, "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; - } - PrintAndLogEx(WARNING, "Invalid char on input"); - return 0; - } - - if (crc) { - AddCrc(data, datalen); - datalen += 2; - } - - c.arg[0] = datalen; - c.arg[1] = fast; - c.arg[2] = reply; - memcpy(c.d.asBytes, data, datalen); + // strip + while (*Cmd == ' ' || *Cmd == '\t') Cmd++; - clearCommandBuffer(); - SendCommand(&c); - - if (reply) { - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - uint8_t len = resp.arg[0]; - PrintAndLogEx(NORMAL, "received %i octets", len); - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.d.asBytes, len) ); - } else { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - } - } - return 0; -} + 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 '2': + fast = 0; + break; + case 'c': + case 'C': + crc = true; + break; + default: + PrintAndLogEx(WARNING, "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++; -/** - * parses common HF 15 CMD parameters and prepares some data structures - * Parameters: - * **cmd command line - */ -int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd) { - int temp; - uint8_t *req = c->d.asBytes; - uint8_t uid[8] = {0x00}; - uint32_t reqlen = 0; + if (strlen(buf) >= 2) { + sscanf(buf, "%x", &temp); + data[datalen] = (uint8_t)(temp & 0xff); + datalen++; + *buf = 0; + } + continue; + } + PrintAndLogEx(WARNING, "Invalid char on input"); + return 0; + } - // strip - while (**cmd==' ' || **cmd=='\t') (*cmd)++; - - if (strstr(*cmd, "-2") == *cmd) { - c->arg[1] = 0; // use 1of256 - (*cmd) += 2; - } + if (crc) { + AddCrc15(data, datalen); + datalen += 2; + } - // strip - while (**cmd==' ' || **cmd=='\t') (*cmd)++; - - if (strstr(*cmd, "-o") == *cmd) { - req[reqlen] = ISO15_REQ_OPTION; - (*cmd) += 2; - } - - // strip - while (**cmd == ' ' || **cmd == '\t') (*cmd)++; - - switch (**cmd) { - case 0: - PrintAndLogEx(WARNING, "missing addr"); - return 0; - break; - case 'u': - case 'U': - // unaddressed mode may not be supported by all vendors - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY; - req[reqlen++] = iso15cmd; - break; - case '*': - // we scan for the UID ourself - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[reqlen++] = iso15cmd; + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, datalen, fast, reply, data, datalen); - if (!getUID(uid)) { - PrintAndLogEx(WARNING, "No tag found"); - return 0; - } - memcpy(&req[reqlen], uid, sizeof(uid)); - PrintAndLogEx(NORMAL, "Detected UID %s", sprintUID(NULL, uid)); - reqlen += sizeof(uid); - break; - default: - req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[reqlen++] = iso15cmd; - - // parse UID - for (int i=0; i<8 && (*cmd)[i*2] && (*cmd)[i*2+1]; i++) { - sscanf((char[]){(*cmd)[i*2], (*cmd)[i*2+1],0}, "%X", &temp); - uid[7-i] = temp & 0xff; - } - - PrintAndLogEx(NORMAL, "Using UID %s", sprintUID(NULL, uid)); - memcpy(&req[reqlen], uid, sizeof(uid)); - reqlen += sizeof(uid); - break; - } - // skip to next space - while (**cmd!=' ' && **cmd!='\t') (*cmd)++; - // skip over the space - while (**cmd==' ' || **cmd=='\t') (*cmd)++; - - c->arg[0] = reqlen; - return 1; + if (reply) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + uint8_t len = resp.oldarg[0]; + PrintAndLogEx(NORMAL, "received %i octets", len); + PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + } else { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + } + } + return 0; } /** * Commandline handling: HF15 CMD READMULTI * Read multiple blocks at once (not all tags support this) */ -int CmdHF15Readmulti(const char *Cmd) { +static int CmdHF15Readmulti(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd)<3 || cmdp == 'h' || cmdp == 'H') return usage_15_readmulti(); + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_readmulti(); - UsbCommand resp; - uint8_t *recv; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - uint8_t *req = c.d.asBytes; - int reqlen = 0; - uint8_t pagenum, pagecount; - char cmdbuf[100]; - char *cmd = cmdbuf; - strncpy(cmd, Cmd, 99); + PacketResponseNG resp; + uint8_t *recv; + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + uint8_t pagenum, pagecount; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); - if ( !prepareHF15Cmd(&cmd, &c, ISO15_CMD_READMULTI) ) - return 0; + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READMULTI)) + return 0; - // add OPTION flag, in order to get lock-info - req[0] |= ISO15_REQ_OPTION; - - reqlen = c.arg[0]; + // add OPTION flag, in order to get lock-info + req[0] |= ISO15_REQ_OPTION; - // decimal - pagenum = param_get8ex(cmd, 0, 0, 10); - pagecount = param_get8ex(cmd, 1, 0, 10); + // decimal + pagenum = param_get8ex(cmd, 0, 0, 10); + pagecount = param_get8ex(cmd, 1, 0, 10); - //PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount); - - // 0 means 1 page, - // 1 means 2 pages, ... - if (pagecount > 0) pagecount--; - - req[reqlen++] = pagenum; - req[reqlen++] = pagecount; - AddCrc(req, reqlen); - c.arg[0] = reqlen+2; + //PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount); - clearCommandBuffer(); - SendCommand(&c); - - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; - } - - uint32_t status = resp.arg[0]; - if ( status < 2 ) { - PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; - } + // 0 means 1 page, + // 1 means 2 pages, ... + if (pagecount > 0) pagecount--; - recv = resp.d.asBytes; - - if (!CheckCrc(recv, status)) { - PrintAndLogEx(FAILED, "CRC failed"); - return 2; - } - - if ( recv[0] & ISO15_RES_ERROR ) { - PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; - } + req[reqlen++] = pagenum; + req[reqlen++] = pagecount; + AddCrc15(req, reqlen); + reqlen += 2; - int start = 1; // skip status byte - int stop = (pagecount+1) * 5; - int currblock = pagenum; - // print response - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); - PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); - for (int i = start; i < stop; i += 5) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", currblock, currblock, sprint_hex(recv+i+1, 4 ), recv[i], sprint_ascii(recv+i+1, 4) ); - currblock++; - } + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, reqlen, arg1, 1, req, reqlen); - return 0; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(FAILED, "iso15693 card select failed"); + return 1; + } + + uint32_t status = resp.oldarg[0]; + if (status < 2) { + PrintAndLogEx(FAILED, "iso15693 card select failed"); + return 1; + } + + recv = resp.data.asBytes; + + if (!CheckCrc15(recv, status)) { + PrintAndLogEx(FAILED, "CRC failed"); + return 2; + } + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return 3; + } + + int start = 1; // skip status byte + int stop = (pagecount + 1) * 5; + int currblock = pagenum; + // print response + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); + PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); + for (int i = start; i < stop; i += 5) { + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s | %d | %s", currblock, currblock, sprint_hex(recv + i + 1, 4), recv[i], sprint_ascii(recv + i + 1, 4)); + currblock++; + } + + return 0; } /** * Commandline handling: HF15 CMD READ * Reads a single Block */ -int CmdHF15Read(const char *Cmd) { +static int CmdHF15Read(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd)<3 || cmdp == 'h' || cmdp == 'H') return usage_15_read(); - - UsbCommand resp; - uint8_t *recv; + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_read(); - // UsbCommand arg: len, speed, recv? - // arg0 (datalen, cmd len? .arg0 == crc?) - // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) - // arg2 (recv == 1 == expect a response) - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; - uint8_t *req = c.d.asBytes; - int reqlen = 0, blocknum; - char cmdbuf[100]; - char *cmd = cmdbuf; - strncpy(cmd, Cmd, 99); - - if ( !prepareHF15Cmd(&cmd, &c, ISO15_CMD_READ) ) - return 0; + PacketResponseNG resp; + uint8_t *recv; - // add OPTION flag, in order to get lock-info - req[0] |= ISO15_REQ_OPTION; - - reqlen = c.arg[0]; + // arg: len, speed, recv? + // arg0 (datalen, cmd len? .arg0 == crc?) + // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) + // arg2 (recv == 1 == expect a response) + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int blocknum; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); - blocknum = strtol(cmd, NULL, 0); - - req[reqlen++] = (uint8_t)blocknum; - - AddCrc(req, reqlen); - - c.arg[0] = reqlen+2; + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READ)) + return 0; - clearCommandBuffer(); - SendCommand(&c); + // add OPTION flag, in order to get lock-info + req[0] |= ISO15_REQ_OPTION; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; - } - - uint32_t status = resp.arg[0]; - if ( status < 2 ) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; - } + blocknum = strtol(cmd, NULL, 0); - recv = resp.d.asBytes; - - if ( !CheckCrc(recv, status) ) { - PrintAndLogEx(NORMAL, "CRC failed"); - return 2; - } - - if ( recv[0] & ISO15_RES_ERROR ) { - PrintAndLogEx(WARNING, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; - } - - // print response - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "block #%3d |lck| ascii", blocknum ); - PrintAndLogEx(NORMAL, "------------+---+------" ); - PrintAndLogEx(NORMAL, "%s| %d | %s", sprint_hex(recv+2, status-4), recv[1], sprint_ascii(recv+2, status-4) ); - PrintAndLogEx(NORMAL, ""); - return 0; + req[reqlen++] = (uint8_t)blocknum; + + AddCrc15(req, reqlen); + reqlen += 2; + + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(NORMAL, "iso15693 card select failed"); + return 1; + } + + uint32_t status = resp.oldarg[0]; + if (status < 2) { + PrintAndLogEx(NORMAL, "iso15693 card select failed"); + return 1; + } + + recv = resp.data.asBytes; + + if (!CheckCrc15(recv, status)) { + PrintAndLogEx(NORMAL, "CRC failed"); + return 2; + } + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(WARNING, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return 3; + } + + // print response + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "block #%3d |lck| ascii", blocknum); + PrintAndLogEx(NORMAL, "------------+---+------"); + PrintAndLogEx(NORMAL, "%s| %d | %s", sprint_hex(recv + 2, status - 4), recv[1], sprint_ascii(recv + 2, status - 4)); + PrintAndLogEx(NORMAL, ""); + return 0; } /** * Commandline handling: HF15 CMD WRITE * Writes a single Block - might run into timeout, even when successful */ -int CmdHF15Write(const char *Cmd) { +static int CmdHF15Write(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd)<3 || cmdp == 'h' || cmdp == 'H') return usage_15_write(); - - UsbCommand resp; - uint8_t *recv; - UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - uint8_t *req = c.d.asBytes; - int reqlen = 0, pagenum, temp; - char cmdbuf[100]; - char *cmd = cmdbuf; - char *cmd2; - - strncpy(cmd, Cmd, 99); + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_write(); - if ( !prepareHF15Cmd(&cmd, &c, ISO15_CMD_WRITE) ) - return 0; + PacketResponseNG resp; + uint8_t *recv; + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int pagenum, temp; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + char *cmd2; - reqlen = c.arg[0]; - - // *cmd -> page num ; *cmd2 -> data - cmd2=cmd; - while (*cmd2!=' ' && *cmd2!='\t' && *cmd2) cmd2++; - *cmd2 = 0; - cmd2++; - - pagenum = strtol(cmd, NULL, 0); + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); - req[reqlen++] = (uint8_t)pagenum; - - while (cmd2[0] && cmd2[1]) { // hexdata, read by 2 hexchars - if (*cmd2==' ') { - cmd2++; - continue; - } - sscanf((char[]){cmd2[0],cmd2[1],0},"%X",&temp); - req[reqlen++]=temp & 0xff; - cmd2+=2; - } - AddCrc(req, reqlen); - c.arg[0] = reqlen+2; - - PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x&02X) | data ", pagenum, pagenum); - - clearCommandBuffer(); - SendCommand(&c); + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITE)) + return 0; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway"); - return 1; - } - - uint32_t status = resp.arg[0]; - if ( status < 2 ) { - PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; - } + // *cmd -> page num ; *cmd2 -> data + cmd2 = cmd; + while (*cmd2 != ' ' && *cmd2 != '\t' && *cmd2) cmd2++; + *cmd2 = 0; + cmd2++; - recv = resp.d.asBytes; - - if ( !CheckCrc(recv, status) ) { - PrintAndLogEx(FAILED, "CRC failed"); - return 2; - } - - if ( recv[0] & ISO15_RES_ERROR ) { - PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; - } - - PrintAndLogEx(NORMAL, "OK"); - return 0; + pagenum = strtol(cmd, NULL, 0); + + req[reqlen++] = (uint8_t)pagenum; + + while (cmd2[0] && cmd2[1]) { // hexdata, read by 2 hexchars + if (*cmd2 == ' ') { + cmd2++; + continue; + } + sscanf((char[]) {cmd2[0], cmd2[1], 0}, "%X", &temp); + req[reqlen++] = temp & 0xff; + cmd2 += 2; + } + AddCrc15(req, reqlen); + reqlen += 2; + + PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); + + clearCommandBuffer(); + SendCommandOLD(CMD_ISO_15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway"); + return 1; + } + + uint32_t status = resp.oldarg[0]; + if (status < 2) { + PrintAndLogEx(FAILED, "iso15693 card select failed"); + return 1; + } + + recv = resp.data.asBytes; + + if (!CheckCrc15(recv, status)) { + PrintAndLogEx(FAILED, "CRC failed"); + return 2; + } + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return 3; + } + + PrintAndLogEx(NORMAL, "OK"); + return 0; } -static command_t CommandTable15[] = { - {"help", CmdHF15Help, 1, "This help"}, - {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"}, - {"dump", CmdHF15Dump, 0, "Read all memory pages of an ISO15693 tag, save to file"}, - {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, - {"info", CmdHF15Info, 0, "Tag information"}, - {"list", CmdHF15List, 0, "[Deprecated] List ISO15693 history"}, - {"raw", CmdHF15Raw, 0, "Send raw hex data to tag"}, - {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, - {"record", CmdHF15Record, 0, "Record Samples (ISO15693)"}, - {"restore", CmdHF15Restore, 0, "Restore from file to all memory pages of an ISO15693 tag"}, - {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, - {"samples", CmdHF15Samples, 0, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, - {"read", CmdHF15Read, 0, "Read a block"}, - {"write", CmdHF15Write, 0, "Write a block"}, - {"readmulti", CmdHF15Readmulti, 0, "Reads multiple Blocks"}, - {NULL, NULL, 0, NULL} +static int CmdHF15Restore(const char *Cmd) { + FILE *f; + + uint8_t uid[8] = {0x00}; + char filename[FILE_PATH_SIZE] = {0x00}; + char buff[255] = {0x00}; + size_t blocksize = 4; + uint8_t cmdp = 0; + char newCmdPrefix[FILE_PATH_SIZE + 1] = {0x00}, tmpCmd[FILE_PATH_SIZE + 262] = {0x00}; + char param[FILE_PATH_SIZE] = ""; + char hex[255] = ""; + uint8_t retries = 3, i = 0; + int retval = 0; + + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case '-': + param_getstr(Cmd, cmdp, param, sizeof(param)); + switch (param[1]) { + case '2': + case 'o': + strncpy(newCmdPrefix, " ", sizeof(newCmdPrefix) - 1); + strncat(newCmdPrefix, param, sizeof(newCmdPrefix) - strlen(newCmdPrefix) - 1); + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%s'", param); + return usage_15_restore(); + } + break; + case 'f': + param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + cmdp++; + break; + case 'r': + retries = param_get8ex(Cmd, cmdp + 1, 3, 10); + cmdp++; + break; + case 'b': + blocksize = param_get8ex(Cmd, cmdp + 1, 4, 10); + cmdp++; + break; + case 'u': + param_getstr(Cmd, cmdp + 1, buff, FILE_PATH_SIZE); + cmdp++; + snprintf(filename, sizeof(filename), "hf-15-dump-%s-bin", buff); + break; + case 'h': + return usage_15_restore(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + return usage_15_restore(); + } + cmdp++; + } + + PrintAndLogEx(INFO, "Blocksize: %u", blocksize); + + if (!strlen(filename)) { + PrintAndLogEx(WARNING, "Please provide a filename"); + return usage_15_restore(); + } + + if ((f = fopen(filename, "rb")) == NULL) { + PrintAndLogEx(WARNING, "Could not find file %s", filename); + return 2; + } + + if (!getUID(uid)) { + PrintAndLogEx(WARNING, "No tag found"); + fclose(f); + return 3; + } + + PrintAndLogEx(INFO, "Restoring data blocks."); + + while (1) { + uint8_t tried = 0; + hex[0] = 0x00; + tmpCmd[0] = 0x00; + + size_t bytes_read = fread(buff, 1, blocksize, f); + if (bytes_read == 0) { + PrintAndLogEx(SUCCESS, "File reading done `%s`", filename); + fclose(f); + return 0; + } else if (bytes_read != blocksize) { + PrintAndLogEx(WARNING, "File reading error (%s), %u bytes read instead of %u bytes.", filename, bytes_read, blocksize); + fclose(f); + return 2; + } + + for (int j = 0; j < blocksize; j++) + snprintf(hex + j * 2, 3, "%02X", buff[j]); + + for (int j = 0; j < ARRAYLEN(uid); j++) + snprintf(buff + j * 2, 3, "%02X", uid[j]); + + //TODO: Addressed mode currently not work + //snprintf(tmpCmd, sizeof(tmpCmd), "%s %s %d %s", newCmdPrefix, buff, i, hex); + snprintf(tmpCmd, sizeof(tmpCmd), "%s u %u %s", newCmdPrefix, i, hex); + PrintAndLogEx(DEBUG, "Command to be sent| %s", tmpCmd); + + for (tried = 0; tried < retries; tried++) { + if (!(retval = CmdHF15Write(tmpCmd))) { + break; + } + } + if (tried >= retries) { + fclose(f); + PrintAndLogEx(FAILED, "Restore failed. Too many retries."); + return retval; + } + + i++; + } + fclose(f); + PrintAndLogEx(INFO, "Finish restore"); + return 0; +} + +static command_t CommandTable[] = { + {"help", CmdHF15Help, AlwaysAvailable, "This help"}, + {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"}, + {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"}, + {"findafi", CmdHF15Afi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, + {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, + {"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"}, + {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, + {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, + {"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"}, + {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"}, + {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"}, + {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, + {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, + {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, + {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, + {NULL, NULL, NULL, NULL} }; -int CmdHF15(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable15, Cmd); - return 0; +static int CmdHF15Help(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } -int CmdHF15Help(const char *Cmd) { - CmdsHelp(CommandTable15); - return 0; -} \ No newline at end of file +int CmdHF15(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} + +// used with 'hf search' +int readHF15Uid(bool verbose) { + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + if (!getUID(uid)) { + if (verbose) PrintAndLogEx(WARNING, "No tag found."); + return 0; + } + + PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, uid)); + PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(uid)); + return 1; +} diff --git a/client/cmdhf15.h b/client/cmdhf15.h index 2908a9aab..049e9f68f 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -21,45 +21,13 @@ #include "ui.h" #include "util.h" #include "cmdparser.h" -#include "crc16.h" // iso15 crc +#include "crc16.h" // iso15 crc #include "cmdmain.h" -#include "cmddata.h" // getsamples -#include "loclass/fileutils.h" // savefileEML +#include "cmddata.h" // getsamples +#include "loclass/fileutils.h" // savefileEML int CmdHF15(const char *Cmd); -extern int HF15Reader(const char *Cmd, bool verbose); +int readHF15Uid(bool verbose); -extern int CmdHF15Demod(const char *Cmd); -extern int CmdHF15Samples(const char *Cmd); -extern int CmdHF15Info(const char *Cmd); -extern int CmdHF15Record(const char *Cmd); -extern int CmdHF15Reader(const char *Cmd); -extern int CmdHF15Sim(const char *Cmd); -extern int CmdHF15Afi(const char *Cmd); -extern int CmdHF15Dump(const char*Cmd); -extern int CmdHF15Raw(const char *cmd); -extern int CmdHF15Readmulti(const char *Cmd); -extern int CmdHF15Read(const char *Cmd); -extern int CmdHF15Write(const char *Cmd); - -extern int CmdHF15Help(const char*Cmd); - -// usages -extern int usage_15_demod(void); -extern int usage_15_samples(void); -extern int usage_15_info(void); -extern int usage_15_record(void); -extern int usage_15_reader(void); -extern int usage_15_sim(void); -extern int usage_15_findafi(void); -extern int usage_15_dump(void); -extern int usage_15_restore(void); -extern int usage_15_raw(void); - -extern int usage_15_read(void); -extern int usage_15_write(void); -extern int usage_15_readmulti(void); - -extern int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd); #endif diff --git a/client/cmdhfemv.c b/client/cmdhfemv.c deleted file mode 100644 index ab9396a14..000000000 --- a/client/cmdhfemv.c +++ /dev/null @@ -1,351 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2014 Peter Fillmore -// 2017 iceman -// -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// High frequency EMV commands -//----------------------------------------------------------------------------- -#include "cmdhfemv.h" - -static int CmdHelp(const char *Cmd); - -int usage_hf_emv_test(void){ - PrintAndLogEx(NORMAL, "EMV test "); - PrintAndLogEx(NORMAL, "Usage: hf emv test [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv test"); - return 0; -} -int usage_hf_emv_readrecord(void){ - PrintAndLogEx(NORMAL, "Read a EMV record "); - PrintAndLogEx(NORMAL, "Usage: hf emv readrecord [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : number of records"); - PrintAndLogEx(NORMAL, " : number of SFI records"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv readrecord 1 1"); - return 0; -} -int usage_hf_emv_clone(void){ - PrintAndLogEx(NORMAL, "Usage: hf emv clone [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " : number of records"); - PrintAndLogEx(NORMAL, " : number of SFI records"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv clone 10 10"); - return 0; -} -int usage_hf_emv_transaction(void){ - PrintAndLogEx(NORMAL, "Performs EMV reader transaction"); - PrintAndLogEx(NORMAL, "Usage: hf emv trans [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv trans"); - return 0; -} -int usage_hf_emv_getrnd(void){ - PrintAndLogEx(NORMAL, "retrieve the UN number from a terminal"); - PrintAndLogEx(NORMAL, "Usage: hf emv getrnd [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv getrnd"); - return 0; -} -int usage_hf_emv_eload(void){ - PrintAndLogEx(NORMAL, "set EMV tags in the device to use in a transaction"); - PrintAndLogEx(NORMAL, "Usage: hf emv eload [h] o "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : filename w/o '.bin'"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv eload o myfile"); - return 0; -} -int usage_hf_emv_dump(void){ - PrintAndLogEx(NORMAL, "Gets EMV contactless tag values."); - PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLogEx(NORMAL, "Usage: hf emv dump [h] o "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " o : filename w/o '.bin' to dump bytes"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv dump"); - PrintAndLogEx(NORMAL, " hf emv dump o myfile"); - return 0; -} -int usage_hf_emv_sim(void){ - PrintAndLogEx(NORMAL, "Simulates a EMV contactless card"); - PrintAndLogEx(NORMAL, "Usage: hf emv sim [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf emv sim"); - return 0; -} - -int CmdHfEmvTest(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_test(); - - UsbCommand c = {CMD_EMV_TEST, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk: %02x", isOK); - return 0; -} - -int CmdHfEmvReadRecord(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_readrecord(); - - uint8_t record = param_get8(Cmd, 0); - uint8_t sfi = param_getchar(Cmd, 1); - if(record > 32){ - PrintAndLogEx(WARNING, "Record must be less than 32"); - return 1; - } - PrintAndLogEx(NORMAL, "--record no:%02x SFI:%02x ", record, sfi); - - UsbCommand c = {CMD_EMV_READ_RECORD, {record, sfi, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute timeout"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvClone(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ((strlen(Cmd)<3) || cmdp == 'h' || cmdp == 'H') return usage_hf_emv_clone(); - - uint8_t record = param_get8(Cmd, 0); - uint8_t sfi = param_get8(Cmd, 1); - if(record > 32){ - PrintAndLogEx(WARNING, "Record must be less than 32"); - return 1; - } - UsbCommand c = {CMD_EMV_CLONE, {sfi, record, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute timeout"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvTrans(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_transaction(); - - UsbCommand c = {CMD_EMV_TRANSACTION, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 5000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk: %02x", isOK); - print_hex_break(resp.d.asBytes, 512, 32); - return 0; -} -//retrieve the UN number from a terminal -int CmdHfEmvGetrng(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if ( cmdp == 'h' || cmdp == 'H') return usage_hf_emv_getrnd(); - UsbCommand c = {CMD_EMV_GET_RANDOM_NUM, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; -} -//Load a dumped EMV tag on to emulator memory -int CmdHfEmvELoad(const char *Cmd) { - FILE * f; - char filename[FILE_PATH_SIZE]; - char *fnameptr = filename; - int len; - bool errors = false; - uint8_t cmdp = 0; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_eload(); - case 'o': - case 'O': - len = param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE); - if (!len) - errors = true; - if (len > FILE_PATH_SIZE-5) - len = FILE_PATH_SIZE-5; - sprintf(fnameptr + len,".bin"); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_emv_eload(); - - // open file - f = fopen(filename,"r"); - if (!f) { - PrintAndLogEx(WARNING, "File %s not found or locked", filename); - return 1; - } - - char line[512]; - char *token; - uint16_t tag; - - UsbCommand c = {CMD_EMV_LOAD_VALUE, {0,0,0}}; - - // transfer to device - while (fgets(line, sizeof (line), f)) { - PrintAndLogEx(NORMAL, "LINE = %s\n", line); - - token = strtok(line, ":"); - tag = (uint16_t)strtol(token, NULL, 0); - token = strtok(NULL,""); - - c.arg[0] = tag; - memcpy(c.d.asBytes, token, strlen(token)); - - clearCommandBuffer(); - SendCommand(&c); - - PrintAndLogEx(NORMAL, "Loaded TAG = %04x\n", tag); - PrintAndLogEx(NORMAL, "Loaded VALUE = %s\n", token); - } - - fclose(f); - PrintAndLogEx(NORMAL, "loaded %s", filename); - //PrintAndLogEx(NORMAL, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename); - return 0; -} - -int CmdHfEmvDump(const char *Cmd){ - - bool errors = false; - uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_dump(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_hf_emv_dump(); - - UsbCommand c = {CMD_EMV_DUMP_CARD, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - return 0; -} - -int CmdHfEmvSim(const char *Cmd) { - - bool errors = false; - uint8_t cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_emv_sim(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors) return usage_hf_emv_sim(); - - UsbCommand c = {CMD_EMV_SIM, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "Command execute time-out"); - return 1; - } - uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLogEx(NORMAL, "isOk:%02x", isOK); - return 0; -} - -int CmdHfEmvList(const char *Cmd) { - return CmdTraceList("7816"); -} - -static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"readrecord", CmdHfEmvReadRecord, 0, "EMV Read Record"}, - {"transaction", CmdHfEmvTrans, 0, "Perform EMV Transaction"}, - {"getrng", CmdHfEmvGetrng, 0, "get random number from terminal"}, - {"eload", CmdHfEmvELoad, 0, "load EMV tag into device"}, - {"dump", CmdHfEmvDump, 0, "dump EMV tag values"}, - {"sim", CmdHfEmvSim, 0, "simulate EMV tag"}, - {"clone", CmdHfEmvClone, 0, "clone an EMV tag"}, - {"list", CmdHfEmvList, 0, "[Deprecated] List ISO7816 history"}, - {"test", CmdHfEmvTest, 0, "Test Function"}, - {NULL, NULL, 0, NULL} -}; - -int CmdHFEmv(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; -} - -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; -} \ No newline at end of file diff --git a/client/cmdhfemv.h b/client/cmdhfemv.h deleted file mode 100644 index 0b68a455c..000000000 --- a/client/cmdhfemv.h +++ /dev/null @@ -1,45 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2014 Peter Fillmore -// 2017 iceman -// -// This code is licensed to you under the terms of the GNU GPL, version 2 or, -// at your option, any later version. See the LICENSE.txt file for the text of -// the license. -//----------------------------------------------------------------------------- -// High frequency EMV commands -//----------------------------------------------------------------------------- - -#ifndef CMDHFEMV_H__ -#define CMDHFEMV_H__ - -#include -#include -#include "proxmark3.h" -#include "ui.h" -#include "cmdparser.h" -#include "cmdmain.h" -#include "util.h" -#include "cmdhf.h" // "hf list" - -int CmdHFEmv(const char *Cmd); - -int CmdHfEmvTest(const char *Cmd); -int CmdHfEmvReadRecord(const char *Cmd); -int CmdHfEmvClone(const char *Cmd); -int CmdHfEmvTrans(const char *Cmd); -int CmdHfEmvGetrng(const char *Cmd); -int CmdHfEmvELoad(const char *Cmd); -int CmdHfEmvDump(const char *Cmd); -int CmdHfEmvSim(const char *Cmd); -int CmdHfEmvList(const char *Cmd); - -int usage_hf_emv_test(void); -int usage_hf_emv_readrecord(void); -int usage_hf_emv_clone(void); -int usage_hf_emv_transaction(void); -int usage_hf_emv_getrnd(void); -int usage_hf_emv_eload(void); -int usage_hf_emv_dump(void); -int usage_hf_emv_sim(void); - -#endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index b681810ed..9aeaabefd 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -12,170 +12,170 @@ static int CmdHelp(const char *Cmd); // Perform (part of) the PACE protocol -int CmdHFEPACollectPACENonces(const char *Cmd) -{ - // requested nonce size - uint32_t m = 0; - // requested number of Nonces - uint32_t n = 0; - // delay between requests - uint32_t d = 0; +static int CmdHFEPACollectPACENonces(const char *Cmd) { + // requested nonce size + uint32_t m = 0; + // requested number of Nonces + uint32_t n = 0; + // delay between requests + uint32_t d = 0; - sscanf(Cmd, "%u %u %u", &m, &n, &d); + sscanf(Cmd, "%u %u %u", &m, &n, &d); - // values are expected to be > 0 - m = m > 0 ? m : 1; - n = n > 0 ? n : 1; + // values are expected to be > 0 + m = m > 0 ? m : 1; + n = n > 0 ? n : 1; - PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m); - PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock()/1000); - // repeat n times - for (uint32_t i = 0; i < n; i++) { - // execute PACE - UsbCommand c = {CMD_EPA_PACE_COLLECT_NONCE, {(int)m, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m); + PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000); + // repeat n times + for (uint32_t i = 0; i < n; i++) { + // execute PACE + clearCommandBuffer(); + SendCommandMIX(CMD_EPA_PACE_COLLECT_NONCE, (int)m, 0, 0, NULL, 0); + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); - // check if command failed - if (resp.arg[0] != 0) { - PrintAndLogEx(FAILED, "Error in step %d, Return code: %d",resp.arg[0],(int)resp.arg[1]); - } else { - 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]); - } - // print nonce - PrintAndLogEx(NORMAL, "Length: %d, Nonce: %s", nonce_length, nonce); - free(nonce); - } - if (i < n - 1) { - sleep(d); - } - } - PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock()/1000); - return 1; + // check if command failed + if (resp.oldarg[0] != 0) { + PrintAndLogEx(FAILED, "Error in step %d, Return code: %d", resp.oldarg[0], (int)resp.oldarg[1]); + } else { + size_t nonce_length = resp.oldarg[1]; + char *nonce = (char *) calloc(2 * nonce_length + 1, sizeof(uint8_t)); + for (int j = 0; j < nonce_length; j++) { + sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]); + } + // print nonce + PrintAndLogEx(NORMAL, "Length: %d, Nonce: %s", nonce_length, nonce); + free(nonce); + } + if (i < n - 1) { + sleep(d); + } + } + PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000); + return 1; } // 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}; +static int CmdHFEPAPACEReplay(const char *Cmd) { + // the 4 APDUs which are replayed + their lengths + uint8_t msesa_apdu[41] = {0}, gn_apdu[8] = {0}, map_apdu[75] = {0}; + uint8_t pka_apdu[75] = {0}, ma_apdu[18] = {0}, 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"; + // 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; + // Proxmark response + PacketResponseNG 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) { - PrintAndLogEx(NORMAL, (char *)usage_msg); - PrintAndLogEx(WARNING, "Not enough APDUs! Try again!"); - return 0; - } - skip += skip_add; + int skip = 0, skip_add = 0, scan_return; + // 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) { + PrintAndLogEx(NORMAL, (char *)usage_msg); + PrintAndLogEx(WARNING, "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) { + // break on EOF + if (Cmd[skip] == '\0') { + if (i < sizeof(apdu_lengths) - 1) { - PrintAndLogEx(NORMAL, (char *)usage_msg); - return 0; - } - break; - } - // skip the space - skip++; - } + PrintAndLogEx(NORMAL, (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; + // transfer the APDUs to the Proxmark + uint8_t data[PM3_CMD_DATA_SIZE]; + // fast push mode + conn.block_after_ACK = true; + for (int i = 0; i < sizeof(apdu_lengths); i++) { + // transfer the APDU in several parts if necessary + for (int j = 0; j * sizeof(data) < apdu_lengths[i]; j++) { + // amount of data in this packet + int packet_length = apdu_lengths[i] - (j * sizeof(data)); + if (packet_length > sizeof(data)) { + packet_length = sizeof(data); + } + if ((i == sizeof(apdu_lengths) - 1) && (j * sizeof(data) >= apdu_lengths[i] - 1)) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + memcpy(data, // + (j * sizeof(data)), + apdus[i] + (j * sizeof(data)), + packet_length); - memcpy(usb_cmd.d.asBytes, // + (j * sizeof(usb_cmd.d.asBytes)), - apdus[i] + (j * sizeof(usb_cmd.d.asBytes)), - packet_length); - - clearCommandBuffer(); - SendCommand(&usb_cmd); - WaitForResponse(CMD_ACK, &resp); - if (resp.arg[0] != 0) { - PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j); - return 0; - } - } - } + clearCommandBuffer(); + // arg0: APDU number + // arg1: offset into the APDU + SendCommandOLD(CMD_EPA_PACE_REPLAY, i + 1, j * sizeof(data), packet_length, data, packet_length); + WaitForResponse(CMD_ACK, &resp); + if (resp.oldarg[0] != 0) { + PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j); + return 0; + } + } + } - // now perform the replay - usb_cmd.arg[0] = 0; - clearCommandBuffer(); - SendCommand(&usb_cmd); - WaitForResponse(CMD_ACK, &resp); - if (resp.arg[0] != 0) { - PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.arg[0]); - PrintAndLogEx(NORMAL, "Measured times:"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.d.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.d.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.d.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.d.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.d.asDwords[4]); - } else { - PrintAndLogEx(NORMAL, "PACE replay successfull!"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.d.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.d.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.d.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.d.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.d.asDwords[4]); - } - return 1; + // now perform the replay + clearCommandBuffer(); + SendCommandMIX(CMD_EPA_PACE_REPLAY, 0, 0, 0, NULL, 0); + WaitForResponse(CMD_ACK, &resp); + if (resp.oldarg[0] != 0) { + PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); + PrintAndLogEx(NORMAL, "Measured times:"); + PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + } else { + PrintAndLogEx(NORMAL, "PACE replay successfull!"); + PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + } + return 1; } static 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} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"cnonces", CmdHFEPACollectPACENonces, IfPm3Iso14443, " Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"}, + {"preplay", CmdHFEPAPACEReplay, IfPm3Iso14443, " Perform PACE protocol by replaying given APDUs"}, + {NULL, NULL, NULL, NULL} }; -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } int CmdHFEPA(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; -} \ No newline at end of file + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/cmdhfepa.h b/client/cmdhfepa.h index 914ce4c5d..c08fa8ea0 100644 --- a/client/cmdhfepa.h +++ b/client/cmdhfepa.h @@ -25,8 +25,6 @@ #include "util_posix.h" -extern int CmdHFEPA(const char *Cmd); -extern int CmdHFEPACollectPACENonces(const char *Cmd); -extern int CmdHFEPAPACEReplay(const char *Cmd); +int CmdHFEPA(const char *Cmd); #endif // CMDHFEPA_H__ diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 25baca523..6f3e28737 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -11,435 +11,441 @@ static int CmdHelp(const char *Cmd); -int usage_hf_felica_sim(void) { - PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa tag \n"); - PrintAndLogEx(NORMAL, "Usage: hf felica sim [h] t [v]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " t : 1 = FeliCa"); - PrintAndLogEx(NORMAL, " : 2 = FeliCaLiteS"); - PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf felica sim t 1 "); - return 0; +static int usage_hf_felica_sim(void) { + PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa tag \n"); + PrintAndLogEx(NORMAL, "Usage: hf felica sim [h] t [v]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " t : 1 = FeliCa"); + PrintAndLogEx(NORMAL, " : 2 = FeliCaLiteS"); + PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf felica sim t 1 "); + return 0; } -int usage_hf_felica_sniff(void){ - PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); - PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list felica'"); - PrintAndLogEx(NORMAL, "Usage: hf felica sniff "); - PrintAndLogEx(NORMAL, " s samples to skip (decimal)"); - PrintAndLogEx(NORMAL, " t triggers to skip (decimal)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf felica sniff s 1000"); - return 0; +static int usage_hf_felica_sniff(void) { + PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); + PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list felica'"); + PrintAndLogEx(NORMAL, "Usage: hf felica sniff "); + PrintAndLogEx(NORMAL, " s samples to skip (decimal)"); + PrintAndLogEx(NORMAL, " t triggers to skip (decimal)"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf felica sniff s 1000"); + return 0; } -int usage_hf_felica_simlite(void) { - PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa Lite tag \n"); - PrintAndLogEx(NORMAL, "Usage: hf felica litesim [h] u "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " uid : UID in hexsymbol"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf felica litesim 11223344556677"); - return 0; +static int usage_hf_felica_simlite(void) { + PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa Lite tag \n"); + PrintAndLogEx(NORMAL, "Usage: hf felica litesim [h] u "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " uid : UID in hexsymbol"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf felica litesim 11223344556677"); + return 0; } -int usage_hf_felica_dumplite(void) { - PrintAndLogEx(NORMAL, "\n Dump ISO/18092 FeliCa Lite tag \n"); - PrintAndLogEx(NORMAL, "press button to abort run, otherwise it will loop for 200sec."); - PrintAndLogEx(NORMAL, "Usage: hf felica litedump [h]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf felica litedump"); - return 0; +static int usage_hf_felica_dumplite(void) { + PrintAndLogEx(NORMAL, "\n Dump ISO/18092 FeliCa Lite tag \n"); + PrintAndLogEx(NORMAL, "press button to abort run, otherwise it will loop for 200sec."); + PrintAndLogEx(NORMAL, "Usage: hf felica litedump [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf felica litedump"); + return 0; } -int usage_hf_felica_raw(void){ - PrintAndLogEx(NORMAL, "Usage: hf felica raw [-h] [-r] [-c] [-p] [-a] <0A 0B 0C ... hex>"); - PrintAndLogEx(NORMAL, " -h this help"); - PrintAndLogEx(NORMAL, " -r do not read response"); - PrintAndLogEx(NORMAL, " -c calculate and append CRC"); - PrintAndLogEx(NORMAL, " -p leave the signal field ON after receive"); - PrintAndLogEx(NORMAL, " -a active signal field ON without select"); - PrintAndLogEx(NORMAL, " -s active signal field ON with select"); - return 0; +static int usage_hf_felica_raw(void) { + PrintAndLogEx(NORMAL, "Usage: hf felica raw [-h] [-r] [-c] [-p] [-a] <0A 0B 0C ... hex>"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -r do not read response"); + PrintAndLogEx(NORMAL, " -c calculate and append CRC"); + PrintAndLogEx(NORMAL, " -p leave the signal field ON after receive"); + PrintAndLogEx(NORMAL, " -a active signal field ON without select"); + PrintAndLogEx(NORMAL, " -s active signal field ON with select"); + return 0; } -int CmdHFFelicaList(const char *Cmd) { - //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead"); - CmdTraceList("raw"); - return 0; +static int CmdHFFelicaList(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list felica' instead"); + CmdTraceList("felica"); + return 0; } -int CmdHFFelicaReader(const char *Cmd) { - bool silent = (Cmd[0] == 's' || Cmd[0] == 'S'); - //UsbCommand cDisconnect = {CMD_FELICA_COMMAND, {0,0,0}}; - UsbCommand c = {CMD_FELICA_COMMAND, {FELICA_CONNECT, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - if (!silent) PrintAndLogEx(WARNING, "FeliCa card select failed"); - //SendCommand(&cDisconnect); - return 0; - } - - felica_card_select_t card; - memcpy(&card, (felica_card_select_t *)resp.d.asBytes, sizeof(felica_card_select_t)); - uint64_t status = resp.arg[0]; - - switch(status) { - case 1: { - if (!silent) - PrintAndLogEx(WARNING, "card timeout"); - break; - } - case 2: { - if (!silent) - PrintAndLogEx(WARNING, "card answered wrong"); - break; - } - case 3: { - if (!silent) - PrintAndLogEx(WARNING, "CRC check failed"); - break; - } - case 0: { - PrintAndLogEx(SUCCESS, "FeliCa tag info"); - - PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); - PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); - PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); - - PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); - PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); - PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); - - PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); - break; - } - } - return status; +static int CmdHFFelicaReader(const char *Cmd) { + bool verbose = !(Cmd[0] == 's' || Cmd[0] == 'S'); + readFelicaUid(verbose); + return 0; } // simulate iso18092 / FeliCa tag -int CmdHFFelicaSim(const char *Cmd) { - bool errors = false; - uint8_t flags = 0; - uint8_t tagtype = 1; - uint8_t cmdp = 0; - uint8_t uid[10] = {0,0,0,0,0,0,0,0,0,0}; - int uidlen = 0; - bool verbose = false; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_felica_sim(); - case 't': - case 'T': - // Retrieve the tag type - tagtype = param_get8ex(Cmd, cmdp+1, 0, 10); - if (tagtype == 0) - errors = true; - cmdp += 2; - break; - case 'u': - case 'U': - // Retrieve the full 4,7,10 byte long uid - param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); - if (!errors) { - PrintAndLogEx(NORMAL, "Emulating ISO18092/FeliCa tag with %d byte UID (%s)", uidlen>>1, sprint_hex(uid, uidlen>>1)); - } - cmdp += 2; - break; - case 'v': - case 'V': - verbose = true; - cmdp++; - break; - case 'e': - case 'E': - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } +static int CmdHFFelicaSim(const char *Cmd) { + bool errors = false; + uint8_t flags = 0; + uint8_t tagtype = 1; + uint8_t cmdp = 0; + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int uidlen = 0; + bool verbose = false; - //Validations - if (errors || cmdp == 0) return usage_hf_felica_sim(); - - UsbCommand c = {CMD_FELICA_SIMULATE_TAG,{ tagtype, flags, 0 }}; - memcpy(c.d.asBytes, uid, uidlen>>1); - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - if ( verbose ) - PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation"); - - while( !ukbhit() ){ - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) continue; - } - return 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_hf_felica_sim(); + case 't': + case 'T': + // Retrieve the tag type + tagtype = param_get8ex(Cmd, cmdp + 1, 0, 10); + if (tagtype == 0) + errors = true; + cmdp += 2; + break; + case 'u': + case 'U': + // Retrieve the full 4,7,10 byte long uid + param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen); + if (!errors) { + PrintAndLogEx(NORMAL, "Emulating ISO18092/FeliCa tag with %d byte UID (%s)", uidlen >> 1, sprint_hex(uid, uidlen >> 1)); + } + cmdp += 2; + break; + case 'v': + case 'V': + verbose = true; + cmdp++; + break; + case 'e': + case 'E': + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || cmdp == 0) return usage_hf_felica_sim(); + + clearCommandBuffer(); + SendCommandOLD(CMD_FELICA_SIMULATE_TAG, tagtype, flags, 0, uid, uidlen >> 1); + PacketResponseNG resp; + + if (verbose) + PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation"); + + while (!ukbhit()) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue; + } + return 0; } -int CmdHFFelicaSniff(const char *Cmd) { +static int CmdHFFelicaSniff(const char *Cmd) { - uint8_t cmdp = 0; - uint64_t samples2skip = 0; - uint64_t triggers2skip = 0; - bool errors = false; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_hf_felica_sniff(); - case 's': - case 'S': - samples2skip = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 't': - case 'T': - triggers2skip = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - //Validations - if (errors || cmdp == 0) return usage_hf_felica_sniff(); - - UsbCommand c = {CMD_FELICA_SNOOP, {samples2skip, triggers2skip, 0}}; - clearCommandBuffer(); - SendCommand(&c); - return 0; + uint8_t cmdp = 0; + uint64_t samples2skip = 0; + uint64_t triggers2skip = 0; + bool errors = false; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_hf_felica_sniff(); + case 's': + case 'S': + samples2skip = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 't': + case 'T': + triggers2skip = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || cmdp == 0) return usage_hf_felica_sniff(); + + clearCommandBuffer(); + SendCommandMIX(CMD_FELICA_SNIFF, samples2skip, triggers2skip, 0, NULL, 0); + return 0; } // uid hex -int CmdHFFelicaSimLite(const char *Cmd) { +static int CmdHFFelicaSimLite(const char *Cmd) { - uint64_t uid = param_get64ex(Cmd, 0, 0, 16); + uint64_t uid = param_get64ex(Cmd, 0, 0, 16); if (!uid) - return usage_hf_felica_simlite(); - - UsbCommand c = {CMD_FELICA_LITE_SIM, {uid, 0, 0} }; - clearCommandBuffer(); - SendCommand(&c); - return 0; + return usage_hf_felica_simlite(); + + clearCommandBuffer(); + SendCommandMIX(CMD_FELICA_LITE_SIM, uid, 0, 0, NULL, 0); + return 0; } - + static void printSep() { - PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); + PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); } -uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace,uint16_t tracelen) { - if (tracepos+19 >= tracelen) - return tracelen; - - trace += tracepos; - uint8_t blocknum = trace[0]; - uint8_t status1 = trace[1]; - uint8_t status2 = trace[2]; +static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) { + if (tracepos + 19 >= tracelen) + return tracelen; - char line[110] = {0}; - for (int j = 0; j < 16; j++) { - snprintf(line+( j * 4),110, "%02x ", trace[j+3]); - } + trace += tracepos; + uint8_t blocknum = trace[0]; + uint8_t status1 = trace[1]; + uint8_t status2 = trace[2]; - PrintAndLogEx(NORMAL, "block number %02x, status: %02x %02x",blocknum,status1, status2); - switch (blocknum) { - case 0x00: PrintAndLogEx(NORMAL, "S_PAD0: %s",line);break; - case 0x01: PrintAndLogEx(NORMAL, "S_PAD1: %s",line);break; - case 0x02: PrintAndLogEx(NORMAL, "S_PAD2: %s",line);break; - case 0x03: PrintAndLogEx(NORMAL, "S_PAD3: %s",line);break; - case 0x04: PrintAndLogEx(NORMAL, "S_PAD4: %s",line);break; - case 0x05: PrintAndLogEx(NORMAL, "S_PAD5: %s",line);break; - case 0x06: PrintAndLogEx(NORMAL, "S_PAD6: %s",line);break; - case 0x07: PrintAndLogEx(NORMAL, "S_PAD7: %s",line);break; - case 0x08: PrintAndLogEx(NORMAL, "S_PAD8: %s",line);break; - case 0x09: PrintAndLogEx(NORMAL, "S_PAD9: %s",line);break; - case 0x0a: PrintAndLogEx(NORMAL, "S_PAD10: %s",line);break; - case 0x0b: PrintAndLogEx(NORMAL, "S_PAD11: %s",line);break; - case 0x0c: PrintAndLogEx(NORMAL, "S_PAD12: %s",line);break; - case 0x0d: PrintAndLogEx(NORMAL, "S_PAD13: %s",line);break; - case 0x0E: { - uint32_t regA = trace[3] + (trace[4]>>8) + (trace[5]>>16) + (trace[6]>>24); - uint32_t regB = trace[7] + (trace[8]>>8) + (trace[9]>>16) + (trace[10]>>24); - line[0] = 0; - for (int j = 0; j < 8; j++) - snprintf(line+( j * 2),110, "%02x", trace[j+11]); - PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line); - } - break; - case 0x80: PrintAndLogEx(NORMAL, "Random Challenge, WO: %s ", line); break; - case 0x81: PrintAndLogEx(NORMAL, "MAC, only set on dual read: %s ", line); break; - case 0x82: { - char idd[20]; - char idm[20]; - for (int j = 0; j < 8; j++) - snprintf(idd+( j * 2),20, "%02x", trace[j+3]); - - for (int j = 0; j < 6; j++) - snprintf(idm+( j * 2),20, "%02x", trace[j+13]); - - PrintAndLogEx(NORMAL, "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd, trace[11], trace [12], idm); - } - break; - case 0x83: { - char idm[20]; - char pmm[20]; - for (int j = 0; j < 8; j++) - snprintf(idm+( j * 2),20, "%02x", trace[j+3]); - - for (int j = 0; j < 8; j++) - snprintf(pmm+( j * 2),20, "%02x", trace[j+11]); - - PrintAndLogEx(NORMAL, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm); - } - break; - case 0x84: PrintAndLogEx(NORMAL, "SER_C: 0x%02x%02x ", trace[3], trace[4]); break; - case 0x85: PrintAndLogEx(NORMAL, "SYS_Cl 0x%02x%02x ", trace[3], trace[4]); break; - case 0x86: PrintAndLogEx(NORMAL, "CKV (key version): 0x%02x%02x ", trace[3], trace[4]); break; - case 0x87: PrintAndLogEx(NORMAL, "CK (card key), WO: %s ", line); break; - case 0x88: { - PrintAndLogEx(NORMAL, "Memory Configuration (MC):"); - PrintAndLogEx(NORMAL, "MAC needed to write state: %s", trace[3+12]? "on" : "off"); - //order might be off here... - PrintAndLogEx(NORMAL, "Write with MAC for S_PAD : %s ", sprint_bin(trace+3+10, 2) ); - PrintAndLogEx(NORMAL, "Write with AUTH for S_PAD : %s ", sprint_bin(trace+3+8, 2) ); - PrintAndLogEx(NORMAL, "Read after AUTH for S_PAD : %s ", sprint_bin(trace+3+6, 2) ); - PrintAndLogEx(NORMAL, "MAC needed to write CK and CKV: %s", trace[3+5] ? "on" : "off"); - PrintAndLogEx(NORMAL, "RF parameter: %02x", (trace[3+4] & 0x7) ); - PrintAndLogEx(NORMAL, "Compatible with NDEF: %s", trace[3+3] ? "yes" : "no"); - PrintAndLogEx(NORMAL, "Memory config writable : %s", (trace[3+2] == 0xff) ? "yes" : "no"); - PrintAndLogEx(NORMAL, "RW access for S_PAD : %s ", sprint_bin(trace+3, 2) ); - } - break; - case 0x90: { + char line[110] = {0}; + for (int j = 0; j < 16; j++) { + snprintf(line + (j * 4), sizeof(line) - 1 - (j * 4), "%02x ", trace[j + 3]); + } + + PrintAndLogEx(NORMAL, "block number %02x, status: %02x %02x", blocknum, status1, status2); + switch (blocknum) { + case 0x00: + PrintAndLogEx(NORMAL, "S_PAD0: %s", line); + break; + case 0x01: + PrintAndLogEx(NORMAL, "S_PAD1: %s", line); + break; + case 0x02: + PrintAndLogEx(NORMAL, "S_PAD2: %s", line); + break; + case 0x03: + PrintAndLogEx(NORMAL, "S_PAD3: %s", line); + break; + case 0x04: + PrintAndLogEx(NORMAL, "S_PAD4: %s", line); + break; + case 0x05: + PrintAndLogEx(NORMAL, "S_PAD5: %s", line); + break; + case 0x06: + PrintAndLogEx(NORMAL, "S_PAD6: %s", line); + break; + case 0x07: + PrintAndLogEx(NORMAL, "S_PAD7: %s", line); + break; + case 0x08: + PrintAndLogEx(NORMAL, "S_PAD8: %s", line); + break; + case 0x09: + PrintAndLogEx(NORMAL, "S_PAD9: %s", line); + break; + case 0x0a: + PrintAndLogEx(NORMAL, "S_PAD10: %s", line); + break; + case 0x0b: + PrintAndLogEx(NORMAL, "S_PAD11: %s", line); + break; + case 0x0c: + PrintAndLogEx(NORMAL, "S_PAD12: %s", line); + break; + case 0x0d: + PrintAndLogEx(NORMAL, "S_PAD13: %s", line); + break; + case 0x0E: { + uint32_t regA = trace[3] | trace[4] << 8 | trace[5] << 16 | trace[ 6] << 24; + uint32_t regB = trace[7] | trace[8] << 8 | trace[9] << 16 | trace[10] << 24; + line[0] = 0; + for (int j = 0; j < 8; j++) + snprintf(line + (j * 2), sizeof(line) - 1 - (j * 2), "%02x", trace[j + 11]); + + PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line); + } + break; + case 0x80: + PrintAndLogEx(NORMAL, "Random Challenge, WO: %s ", line); + break; + case 0x81: + PrintAndLogEx(NORMAL, "MAC, only set on dual read: %s ", line); + break; + case 0x82: { + char idd[20]; + char idm[20]; + for (int j = 0; j < 8; j++) + snprintf(idd + (j * 2), sizeof(idd) - 1 - (j * 2), "%02x", trace[j + 3]); + + for (int j = 0; j < 6; j++) + snprintf(idm + (j * 2), sizeof(idm) - 1 - (j * 2), "%02x", trace[j + 13]); + + PrintAndLogEx(NORMAL, "ID Block, IDd: 0x%s DFC: 0x%02x%02x Arb: %s ", idd, trace[11], trace [12], idm); + } + break; + case 0x83: { + char idm[20]; + char pmm[20]; + for (int j = 0; j < 8; j++) + snprintf(idm + (j * 2), sizeof(idm) - 1 - (j * 2), "%02x", trace[j + 3]); + + for (int j = 0; j < 8; j++) + snprintf(pmm + (j * 2), sizeof(pmm) - 1 - (j * 2), "%02x", trace[j + 11]); + + PrintAndLogEx(NORMAL, "DeviceId: IDm: 0x%s PMm: 0x%s ", idm, pmm); + } + break; + case 0x84: + PrintAndLogEx(NORMAL, "SER_C: 0x%02x%02x ", trace[3], trace[4]); + break; + case 0x85: + PrintAndLogEx(NORMAL, "SYS_Cl 0x%02x%02x ", trace[3], trace[4]); + break; + case 0x86: + PrintAndLogEx(NORMAL, "CKV (key version): 0x%02x%02x ", trace[3], trace[4]); + break; + case 0x87: + PrintAndLogEx(NORMAL, "CK (card key), WO: %s ", line); + break; + case 0x88: { + PrintAndLogEx(NORMAL, "Memory Configuration (MC):"); + PrintAndLogEx(NORMAL, "MAC needed to write state: %s", trace[3 + 12] ? "on" : "off"); + //order might be off here... + PrintAndLogEx(NORMAL, "Write with MAC for S_PAD : %s ", sprint_bin(trace + 3 + 10, 2)); + PrintAndLogEx(NORMAL, "Write with AUTH for S_PAD : %s ", sprint_bin(trace + 3 + 8, 2)); + PrintAndLogEx(NORMAL, "Read after AUTH for S_PAD : %s ", sprint_bin(trace + 3 + 6, 2)); + PrintAndLogEx(NORMAL, "MAC needed to write CK and CKV: %s", trace[3 + 5] ? "on" : "off"); + PrintAndLogEx(NORMAL, "RF parameter: %02x", (trace[3 + 4] & 0x7)); + PrintAndLogEx(NORMAL, "Compatible with NDEF: %s", trace[3 + 3] ? "yes" : "no"); + PrintAndLogEx(NORMAL, "Memory config writable : %s", (trace[3 + 2] == 0xff) ? "yes" : "no"); + PrintAndLogEx(NORMAL, "RW access for S_PAD : %s ", sprint_bin(trace + 3, 2)); + } + break; + case 0x90: { PrintAndLogEx(NORMAL, "Write count, RO: %02x %02x %02x ", trace[3], trace[4], trace[5]); - } - break; - case 0x91: { + } + break; + case 0x91: { PrintAndLogEx(NORMAL, "MAC_A, RW (auth): %s ", line); - } - break; - case 0x92: + } + break; + case 0x92: PrintAndLogEx(NORMAL, "State:"); - PrintAndLogEx(NORMAL, "Polling disabled: %s", trace[3+8] ? "yes" : "no"); + PrintAndLogEx(NORMAL, "Polling disabled: %s", trace[3 + 8] ? "yes" : "no"); PrintAndLogEx(NORMAL, "Authenticated: %s", trace[3] ? "yes" : "no"); - break; - case 0xa0: - PrintAndLogEx(NORMAL, "CRC of all bloacks match : %s", (trace[3+2]==0xff) ? "no" : "yes"); - break; - default: - PrintAndLogEx(WARNING, "INVALID %d: %s", blocknum, line); - break; - } - return tracepos+19; + break; + case 0xa0: + PrintAndLogEx(NORMAL, "CRC of all bloacks match : %s", (trace[3 + 2] == 0xff) ? "no" : "yes"); + break; + default: + PrintAndLogEx(WARNING, "INVALID %d: %s", blocknum, line); + break; + } + return tracepos + 19; } -int CmdHFFelicaDumpLite(const char *Cmd) { +static int CmdHFFelicaDumpLite(const char *Cmd) { - char ctmp = param_getchar(Cmd, 0); - if ( ctmp == 'h' || ctmp == 'H') return usage_hf_felica_dumplite(); + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_hf_felica_dumplite(); - PrintAndLogEx(SUCCESS, "FeliCa lite - dump started"); - PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); - UsbCommand c = {CMD_FELICA_LITE_DUMP, {0,0,0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - - uint8_t timeout = 0; - while ( !WaitForResponseTimeout(CMD_ACK, &resp, 2000) ) { - timeout++; - printf("."); fflush(stdout); - if (ukbhit()) { - int gc = getchar(); (void)gc; - PrintAndLogEx(NORMAL, "\n[!] aborted via keyboard!\n"); - DropField(); - return 1; - } - if (timeout > 100) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - DropField(); - return 1; - } - } - if (resp.arg[0] == 0) { - PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); - return 1; - } - - uint64_t tracelen = resp.arg[1]; - uint8_t *trace = calloc(tracelen, sizeof(uint8_t)); - if ( trace == NULL ) { - PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); - return 1; - } + PrintAndLogEx(SUCCESS, "FeliCa lite - dump started"); + PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); + clearCommandBuffer(); + SendCommandNG(CMD_FELICA_LITE_DUMP, NULL, 0); + PacketResponseNG resp; - // only download data if there is any. - if ( tracelen > 0 ) { - - if ( !GetFromDevice(BIG_BUF, trace, tracelen, 0, NULL, 2500, false) ){ - PrintAndLogEx(WARNING, "command execution time out"); - free(trace); - return 0; - } - - PrintAndLogEx(SUCCESS, "Recorded Activity (trace len = %d bytes)", tracelen); - - print_hex_break(trace, tracelen, 32); - - printSep(); - uint16_t tracepos = 0; - while (tracepos < tracelen) - tracepos = PrintFliteBlock(tracepos, trace, tracelen); - - printSep(); - } + uint8_t timeout = 0; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + timeout++; + printf("."); + fflush(stdout); + if (ukbhit()) { + int gc = getchar(); + (void)gc; + PrintAndLogEx(WARNING, "\n[!] aborted via keyboard!\n"); + DropField(); + return 1; + } + if (timeout > 100) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + DropField(); + return 1; + } + } + if (resp.oldarg[0] == 0) { + PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); + return 1; + } + + uint64_t tracelen = resp.oldarg[1]; + if (tracelen == 0) + return 1; + + uint8_t *trace = calloc(tracelen, sizeof(uint8_t)); + if (trace == NULL) { + PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); + return 1; + } + + if (!GetFromDevice(BIG_BUF, trace, tracelen, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "command execution time out"); + free(trace); + return 0; + } + + PrintAndLogEx(SUCCESS, "Recorded Activity (trace len = %d bytes)", tracelen); + + print_hex_break(trace, tracelen, 32); + printSep(); + + uint16_t tracepos = 0; + while (tracepos < tracelen) + tracepos = PrintFliteBlock(tracepos, trace, tracelen); + + printSep(); free(trace); - return 0; + return 0; } -int CmdHFFelicaCmdRaw(const char *cmd) { - UsbCommand c = {CMD_FELICA_COMMAND, {0, 0, 0}}; +static void waitCmdFelica(uint8_t iSelect) { + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + uint16_t len = iSelect ? (resp.oldarg[1] & 0xffff) : (resp.oldarg[0] & 0xffff); + PrintAndLogEx(NORMAL, "received %i octets", len); + if (!len) + return; + PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + } else { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + } +} + +static int CmdHFFelicaCmdRaw(const char *Cmd) { bool reply = 1; bool crc = false; bool power = false; bool active = false; bool active_select = false; uint16_t numbits = 0; - char buf[5]=""; + char buf[5] = ""; int i = 0; - uint8_t data[USB_CMD_DATA_SIZE]; - uint16_t datalen = 0; - uint32_t temp; + uint8_t data[PM3_CMD_DATA_SIZE]; + uint16_t datalen = 0; + uint32_t temp; - if (strlen(cmd) < 2) return usage_hf_felica_raw(); + if (strlen(Cmd) < 2) return usage_hf_felica_raw(); // strip - while (*cmd==' ' || *cmd=='\t') cmd++; + 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 'H': - case 'h': - return usage_hf_felica_raw(); - case 'r': + while (Cmd[i] != '\0') { + if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } + if (Cmd[i] == '-') { + switch (Cmd[i + 1]) { + case 'H': + case 'h': + return usage_hf_felica_raw(); + case 'r': reply = false; break; case 'c': @@ -454,12 +460,12 @@ int CmdHFFelicaCmdRaw(const char *cmd) { case 's': active_select = true; break; - case 'b': - sscanf(cmd+i+2, "%d", &temp); + case 'b': + sscanf(Cmd + i + 2, "%d", &temp); numbits = temp & 0xFFFF; - i+=3; - while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } - i-=2; + i += 3; + while (Cmd[i] != ' ' && Cmd[i] != '\0') { i++; } + i -= 2; break; default: return usage_hf_felica_raw(); @@ -467,22 +473,22 @@ int CmdHFFelicaCmdRaw(const char *cmd) { 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]; + 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; - if (++datalen >= sizeof(data)){ - if (crc) - PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); - break; - } + if (strlen(buf) >= 2) { + sscanf(buf, "%x", &temp); + data[datalen] = (uint8_t)(temp & 0xff); + *buf = 0; + if (++datalen >= sizeof(data)) { + if (crc) + PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); + break; + } } continue; } @@ -490,35 +496,33 @@ int CmdHFFelicaCmdRaw(const char *cmd) { return 0; } - if (crc && datalen>0 && datalen < sizeof(data)-2) { + if (crc && datalen > 0 && datalen < sizeof(data) - 2) { uint8_t b1, b2; - compute_crc(CRC_FELICA, data, datalen, &b1, &b2); + compute_crc(CRC_FELICA, data, datalen, &b1, &b2); data[datalen++] = b1; data[datalen++] = b2; } + uint8_t flags = 0; if (active || active_select) { - c.arg[0] |= FELICA_CONNECT; - if(active) - c.arg[0] |= FELICA_NO_SELECT; + flags |= FELICA_CONNECT; + if (active) + flags |= FELICA_NO_SELECT; } if (power) { - c.arg[0] |= FELICA_NO_DISCONNECT; - } - - if (datalen > 0) { - c.arg[0] |= FELICA_RAW; - } - - // Max buffer is USB_CMD_DATA_SIZE - datalen = (datalen > USB_CMD_DATA_SIZE) ? USB_CMD_DATA_SIZE : datalen; - - c.arg[1] = (datalen & 0xFFFF) | (uint32_t)(numbits << 16); - memcpy(c.d.asBytes, data, datalen); + flags |= FELICA_NO_DISCONNECT; + } - clearCommandBuffer(); - SendCommand(&c); + if (datalen > 0) { + flags |= FELICA_RAW; + } + + // Max buffer is PM3_CMD_DATA_SIZE + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; + + clearCommandBuffer(); + SendCommandOLD(CMD_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); if (reply) { if (active_select) @@ -529,41 +533,75 @@ int CmdHFFelicaCmdRaw(const char *cmd) { return 0; } -void waitCmdFelica(uint8_t iSelect) { - UsbCommand resp; - uint16_t len = 0; - - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - len = iSelect ? (resp.arg[1] & 0xffff) : (resp.arg[0] & 0xffff); - PrintAndLogEx(NORMAL, "received %i octets", len); - if(!len) - return; - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.d.asBytes, len) ); - } else { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - } -} - static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHFFelicaList, 0, "[Deprecated] List ISO 18092/FeliCa history"}, - {"reader", CmdHFFelicaReader, 0, "Act like an ISO18092/FeliCa reader"}, - {"sim", CmdHFFelicaSim, 0, " -- Simulate ISO 18092/FeliCa tag"}, - {"sniff", CmdHFFelicaSniff, 0, "sniff ISO 18092/Felica traffic"}, - {"raw", CmdHFFelicaCmdRaw, 0, "Send raw hex data to tag"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, + {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, + {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"}, + {"sniff", CmdHFFelicaSniff, IfPm3Felica, "sniff ISO 18092/Felica traffic"}, + {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, - {"litesim", CmdHFFelicaSimLite, 0, " - only reply to poll request"}, - {"litedump", CmdHFFelicaDumpLite, 0, "Wait for and try dumping FelicaLite"}, - {NULL, NULL, 0, NULL} + {"litesim", CmdHFFelicaSimLite, IfPm3Felica, " - only reply to poll request"}, + {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, + {NULL, NULL, NULL, NULL} }; -int CmdHFFelica(const char *Cmd) { - clearCommandBuffer(); - CmdsParse(CommandTable, Cmd); - return 0; +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; -} \ No newline at end of file +int CmdHFFelica(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} + +int readFelicaUid(bool verbose) { + + clearCommandBuffer(); + SendCommandMIX(CMD_FELICA_COMMAND, FELICA_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (verbose) PrintAndLogEx(WARNING, "FeliCa card select failed"); + //SendCommandMIX(CMD_FELICA_COMMAND, 0, 0, 0, NULL, 0); + return 0; + } + + felica_card_select_t card; + memcpy(&card, (felica_card_select_t *)resp.data.asBytes, sizeof(felica_card_select_t)); + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 1: { + if (verbose) + PrintAndLogEx(WARNING, "card timeout"); + break; + } + case 2: { + if (verbose) + PrintAndLogEx(WARNING, "card answered wrong"); + break; + } + case 3: { + if (verbose) + PrintAndLogEx(WARNING, "CRC check failed"); + break; + } + case 0: { + PrintAndLogEx(SUCCESS, "FeliCa tag info"); + + PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); + PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); + PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); + + PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); + PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); + PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); + + PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); + break; + } + } + return status; +} diff --git a/client/cmdhffelica.h b/client/cmdhffelica.h index f82d2d574..b495b80ec 100644 --- a/client/cmdhffelica.h +++ b/client/cmdhffelica.h @@ -21,26 +21,11 @@ #include "ui.h" #include "util.h" #include "cmdparser.h" -#include "cmdmain.h" -#include "iso14443crc.h" -#include "cmdhf.h" // list cmd -#include "mifare.h" // felica_card_select_t struct +#include "comms.h" // getfromdevice +#include "cmdhf.h" // list cmd +#include "mifare.h" // felica_card_select_t struct -extern int CmdHFFelica(const char *Cmd); -extern int CmdHFFelicaList(const char *Cmd); -extern int CmdHFFelicaReader(const char *Cmd); -extern int CmdHFFelicaSim(const char *Cmd); -extern int CmdHFFelicaSniff(const char *Cmd); -extern int CmdHFFelicaCmdRaw(const char *Cmd); - -extern int usage_hf_felica_sim(void); -extern int usage_hf_felica_sniff(void); -extern int usage_hf_fFelica_raw(void); - -void waitCmdFelica(uint8_t iSelect); - -//temp -extern int CmdHFFelicaSimLite(const char *Cmd); -extern int CmdHFFelicaDumpLite(const char *Cmd); +int CmdHFFelica(const char *Cmd); +int readFelicaUid(bool verbose); #endif diff --git a/client/cmdhffido.c b/client/cmdhffido.c new file mode 100644 index 000000000..39b080dca --- /dev/null +++ b/client/cmdhffido.c @@ -0,0 +1,916 @@ +//----------------------------------------------------------------------------- +// 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 "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); + +static int CmdHFFidoInfo(const char *cmd) { + + if (cmd && strlen(cmd) > 0) + PrintAndLogEx(WARNING, "WARNING: command don't have any parameters.\n"); + + // info about 14a part + infoHF14A(false, false); + + // FIDO info + PrintAndLogEx(NORMAL, "--------------------------------------------"); + SetAPDULogging(false); + + uint8_t buf[APDU_RES_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) + PrintAndLogEx(INFO, "Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + else + PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000."); + + DropField(); + return 0; + } + + if (!strncmp((char *)buf, "U2F_V2", 7)) { + if (!strncmp((char *)buf, "FIDO_2_0", 8)) { + PrintAndLogEx(INFO, "FIDO2 authenricator detected. Version: %.*s", len, buf); + } else { + PrintAndLogEx(INFO, "FIDO authenricator detected (not standard U2F)."); + PrintAndLogEx(INFO, "Non U2F authenticator version:"); + dump_buffer((const unsigned char *)buf, len, NULL, 0); + } + } else { + PrintAndLogEx(INFO, "FIDO U2F authenricator detected. Version: %.*s", len, buf); + } + + res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + return res; + } + if (sw != 0x9000) { + PrintAndLogEx(ERR, "FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + + return 0; + } + + if (buf[0]) { + PrintAndLogEx(ERR, "FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } + + if (len > 1) { + PrintAndLogEx(SUCCESS, "FIDO2 version CBOR decoded:"); + TinyCborPrintFIDOPackage(fido2CmdGetInfo, true, &buf[1], len - 1); + } else { + PrintAndLogEx(ERR, "FIDO2 version length error"); + } + return 0; +} + +static 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) { + PrintAndLogEx(ERR, "ERROR: json error on line %d: %s", error.line, error.text); + *err = true; + return NULL; + } + + if (!json_is_object(root)) { + PrintAndLogEx(ERR, "ERROR: Invalid json format. root must be an object."); + json_decref(root); + *err = true; + return NULL; + } + + } else { + root = json_object(); + } + } + return root; +} + +static 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 > 16) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "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 > 16) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't execute register command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + PrintAndLogEx(NORMAL, ""); + if (APDULogging) + PrintAndLogEx(NORMAL, "---------------------------------------------------------------"); + PrintAndLogEx(NORMAL, "data len: %d", len); + if (verbose2) { + PrintAndLogEx(NORMAL, "--------------data----------------------"); + dump_buffer((const unsigned char *)buf, len, NULL, 0); + PrintAndLogEx(NORMAL, "--------------data----------------------"); + } + + if (buf[0] != 0x05) { + PrintAndLogEx(ERR, "ERROR: First byte must be 0x05, but it %2x", buf[0]); + return 5; + } + PrintAndLogEx(SUCCESS, "User public key: %s", sprint_hex(&buf[1], 65)); + + uint8_t keyHandleLen = buf[66]; + PrintAndLogEx(SUCCESS, "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) { + PrintAndLogEx(NORMAL, "DER certificate[%d]:\n------------------DER-------------------", derLen); + dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL); + PrintAndLogEx(NORMAL, "\n----------------DER---------------------"); + } else { + if (verbose) + PrintAndLogEx(NORMAL, "------------------DER-------------------"); + PrintAndLogEx(NORMAL, "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) { + PrintAndLogEx(NORMAL, "----------------DER TLV-----------------"); + asn1_print(&buf[derp], derLen, " "); + PrintAndLogEx(NORMAL, "----------------DER TLV-----------------"); + } + + FIDOCheckDERAndGetKey(&buf[derp], derLen, verbose, public_key, sizeof(public_key)); + + // get hash + int hashp = 1 + 65 + 1 + keyHandleLen + derLen; + PrintAndLogEx(SUCCESS, "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) { + PrintAndLogEx(NORMAL, " r: %s", sprint_hex(rval, 32)); + PrintAndLogEx(NORMAL, " 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); + //PrintAndLogEx(NORMAL, "--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); + res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[hashp], len - hashp); + if (res) { + if (res == -0x4e00) { + PrintAndLogEx(WARNING, "Signature is NOT VALID."); + } else { + PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res)); + } + } else { + PrintAndLogEx(SUCCESS, "Signature is OK."); + } + + } else { + PrintAndLogEx(WARNING, "Invalid signature. res = %d.", res); + } + + PrintAndLogEx(INFO, "\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) { + PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname); + + // free json object + json_decref(root); + } + + return 0; +}; + +static 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) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "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 > 16) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "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 > 16) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't execute authentication command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + PrintAndLogEx(NORMAL, "---------------------------------------------------------------"); + PrintAndLogEx(SUCCESS, "User presence: %s", (buf[0] ? "verified" : "not verified")); + uint32_t cntr = (uint32_t)bytes_to_num(&buf[1], 4); + PrintAndLogEx(SUCCESS, "Counter: %d", cntr); + PrintAndLogEx(SUCCESS, "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) { + PrintAndLogEx(NORMAL, " r: %s", sprint_hex(rval, 32)); + PrintAndLogEx(NORMAL, " 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); + //PrintAndLogEx(NORMAL, "--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); + res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[5], len - 5); + if (res) { + if (res == -0x4e00) { + PrintAndLogEx(WARNING, "Signature is NOT VALID."); + } else { + PrintAndLogEx(WARNING, "Other signature check error: %x %s", (res < 0) ? -res : res, ecdsa_get_error(res)); + } + } else { + PrintAndLogEx(SUCCESS, "Signature is OK."); + } + } else { + PrintAndLogEx(WARNING, "No public key provided. can't check signature."); + } + } else { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname); + + // free json object + json_decref(root); + } + return 0; +}; + +static void CheckSlash(char *fileName) { + if ((fileName[strlen(fileName) - 1] != '/') && + (fileName[strlen(fileName) - 1] != '\\')) + strcat(fileName, "/"); +} + +static int GetExistsFileNameJson(const char *prefixDir, const 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; +} + +static 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) { + PrintAndLogEx(ERR, "ERROR: Can't found the json file."); + return res; + } + PrintAndLogEx(NORMAL, "fname: %s\n", fname); + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(INFO, "CBOR make credentional request:"); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdMakeCredential, false, data, datalen); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + } + + res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLogEx(ERR, "Can't execute make credential command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + if (buf[0]) { + PrintAndLogEx(ERR, "FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } + + PrintAndLogEx(SUCCESS, "MakeCredential result (%d b) OK.", len); + if (showCBOR) { + PrintAndLogEx(SUCCESS, "CBOR make credentional response:"); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdMakeCredential, true, &buf[1], len - 1); + PrintAndLogEx(NORMAL, "---------------- 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) { + PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname); + } + + json_decref(root); + return 0; +}; + +static 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 " _YELLOW_("`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) { + PrintAndLogEx(ERR, "ERROR: Can't found the json file."); + return res; + } + PrintAndLogEx(NORMAL, "fname: %s\n", fname); + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(ERR, "Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "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) { + PrintAndLogEx(SUCCESS, "CBOR get assertion request:"); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdGetAssertion, false, data, datalen); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + } + + res = FIDO2GetAssertion(data, datalen, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLogEx(ERR, "Can't execute get assertion command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLogEx(ERR, "ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + if (buf[0]) { + PrintAndLogEx(ERR, "FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } + + PrintAndLogEx(SUCCESS, "GetAssertion result (%d b) OK.", len); + if (showCBOR) { + PrintAndLogEx(SUCCESS, "CBOR get assertion response:"); + PrintAndLogEx(NORMAL, "---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdGetAssertion, true, &buf[1], len - 1); + PrintAndLogEx(NORMAL, "---------------- 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) { + PrintAndLogEx(ERR, "ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLogEx(SUCCESS, "File " _YELLOW_("`%s`") " saved.", fname); + } + + json_decref(root); + return 0; +}; + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help."}, + {"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."}, + {"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."}, + {"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, + {"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."}, + {"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFFido(const char *Cmd) { + (void)WaitForResponseTimeout(CMD_ACK, NULL, 100); + return CmdsParse(CommandTable, Cmd); +} + +int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhffido.h b/client/cmdhffido.h new file mode 100644 index 000000000..b54f53118 --- /dev/null +++ b/client/cmdhffido.h @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// 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__ + +int CmdHFFido(const char *Cmd); + + +#endif diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 7f0e3aa07..2bdb91fa1 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -19,2529 +19,2486 @@ static int CmdHelp(const char *Cmd); 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 } + { 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 } }; -int usage_hf_iclass_sim(void) { - PrintAndLogEx(NORMAL, "Usage: hf iclass sim