Merge pull request #1 from iceman1001/master

cross-merging fork to branch from Iceman's repository
This commit is contained in:
grauerfuchs 2018-08-04 20:40:03 -04:00 committed by GitHub
commit 1e48d34612
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
923 changed files with 801471 additions and 22043 deletions

2
.gitattributes vendored
View file

@ -1,4 +1,6 @@
# .gitattributes
# prevent binary files from CRLF handling, diff and merge:
fpga/fpga.bit -crlf -diff
*.bin -crlf -diff
*.z -crlf -diff

31
.gitignore vendored
View file

@ -1,6 +1,7 @@
# .gitignore
# don't push these files to the repository
.history
*.log
*.eml
*.o
@ -12,13 +13,25 @@
*.bin
*.dll
*.moc.cpp
*.z
*.Td
*.DS_Store
*.exe
proxmark
*.dsym
version.c
!client/hardnested/*.bin
!client/hardnested/tables/*.z
client/ui/ui_overlays.h
hardnested_stats.txt
proxmark3
flasher
version.c
lua
luac
fpga_compress
mfkey32
mfkey64
fpga/*
!fpga/tests
@ -32,4 +45,18 @@ fpga/*
!fpga/go.bat
!fpga/sim.tcl
#client/*
# my own traces folder
client/traces/*
*.ice
*.new
armsrc/TEMP EMV/*
tools/mf_nonce_brute/*
tools/andrew/*
ppls patches/*
*- Copy.*
client/lualibs/mf_default_keys.lua
client/lualibs/usb_cmd.lua
# recompiled
fpga_version_info.c

51
.travis.yml Normal file
View file

@ -0,0 +1,51 @@
# Travis-CI Build for IcemanFork/Proxmark3
language: c
#default linux build env is: Ubuntu 14.04 trusty
compiler: gcc
# Test on Linux and MacOS
matrix:
include:
# - os: osx
# osx_image: xcode7.3 # OS X 10.11
# - os: osx
# osx_image: xcode8.3 # OS X 10.12
# - os: osx
# osx_image: xcode9 # OS X 10.13
- os: osx
osx_image: xcode9.1 # OS X 10.13.1
- os: linux
dist: trusty
sudo: required
before_install:
## Install ARM toolchain on Linux.
## add our homebrew tap for MacOS
## Note: all dependencies on MacOS should be resolved by the brew install command
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get update -qq;
sudo apt-get install -y gcc-arm-none-eabi;
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update;
brew tap iceman1001/proxmark3;
fi
install:
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew info proxmark3;
brew options proxmark3;
brew install --HEAD proxmark3;
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
make all;
fi
before_script:
script:
## start and run a test script
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
proxmark3 -h ;
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
./client/proxmark3 -h ;
fi

333
CHANGELOG.md Normal file
View file

@ -0,0 +1,333 @@
# Change Log
All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Added more default keys (@j8048188) (@iceman)
- Added 'sc list/info/raw/reader/upgrade' - (RDV40) smart card module functionality (@iceman)
- Fix 'download eml buffer' (@drandreas)
- Changed 'exclusion of floatingpoint lib' (@pwpiwi)
- Changed 'lua scripts bit32 calls' (@iceman)
- Changed 'hw version' (@pwpiwi), adapted to iceman fork ( @iceman)
- Added 'amiibo functionality' (@jamchamb), adapted to iceman fork ( @iceman)
- Fix 'hf legic' (RDV40) adaptations to FPGA HF enhanched reading distance (@iceman) Thanks to @drandreas!
- Added 'script run mifare_acces' - script to decode Mifare classic accessbits (@Neuromancer)
- Added 'mem load/save/wipe' - commands to upload / download to new RDV40 onboard flashmemory (@iceman)
- Added 'script run mifareplus" - script to communicate with a mifare plus tag (@dceliano)
- Added FlashMemory functionality (RDV40) (Thanks @willok)
- Fix 'hf mfu dump' - partial reads lead to corrupt data (Thanks @elafargue for pointing it out)
- Changed 'hf mfu dump / read' - now retries five times. (@jamchamb)
- Added `hf list mf` - deciphers crypto1 stream and works with first authentication and weak nested authentications (@Merlok)
- Adjusted `lf cmdread` to respond to client when complete and the client will then automatically call `data samples` (@marshmellow42)
- Added a bitbang mode to `lf cmdread` if delay is 0 the cmd bits turn off and on the antenna with 0 and 1 respectively (@marshmellow42)
- dump / restore now uses custom filenames (@brianpow)
- Removed 'hf mf sniff' , (@iceman), use HF 14A SNIFF instead
- Added 'hf iclass lookup' (@iceman)
- Added 'hf iclass chk' (@iceman)
- Fixed ADC mux all closed push-pull state (@iceman)
- Fix 'hf mf darkside' - speed fixes (@pwpiwi)
- Fix 'hw tune' - now compensates for 3% error in output, also measure full 140v using ADC channel 5 and 7. (@iceman)
- Updated loclass gpl license (@holiman)
- Fix Antenna on after changed FPGA Mode. (@iceman)
- Added 'hf mf nack' - Mifare NACK bug detection (@iceman) (@doegox)
- Fix 'hf mf mifare' - zero parity works, no more double runs for normal darkside (@iceman)
- Added 'hf mf fchk' - the fastest check keys implementation tothisday (@iceman)
- Fix 'hf iclass' - more stable demod (@iceman)
- Added 'hf iclass chk' - check keys from default_iclass_keys.dic file (@iceman)
- Fix 'hf 15 dump' - no more crc faults (@iceman)
- Fix 'hf 15 read' - no more crc faults (@iceman)
- Fix 'hf 15 readmulti' - no more crc faults (@iceman)
- Changed proxmark command line parameter `flush` to `-f` or `-flush` (@merlokk)
- Added to proxmark command line parameters `w` - wait 20s for serial port (@merlokk)
- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (@merlokk)
- Added to proxmark ability to execute commands from stdin (pipe) ((@merlokk)
- Added new standalone mode "HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN" (@cjbrigato)
- Added to `hf 14a apdu` - exchange apdu via iso1443-4 (@merlokk)
- Added to `hf 14a apdu` - apdu and tlv results parser (@merlokk)
- Added 'hf emv' commands (@merlokk)
- lots of bug fixes (many many)
### 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)
## [ice.3.1.0][2017-09-26]
- proxmark3 client can reconnect to device without restart (iceman)
- lots of bug fixes (many many)
- trace/securakey-64169.pm3 - trace of a scecurakey (atyppo)
- 'hf mf decrypt' - got some longer input and helptext parameter (iceman)
- Updated the Reveng 1.51 sourcecode to 1.52 from Reveng project homepage (iceman)
- 'hf 14a read' - disconnects when failing to read tag (iceman)
- 'hf mf csave' - renamed parameter 'i' to 'o' as in output (iceman)
## [3.0.0][2017-08-29]
Notes on this release
this version includes a merge with the PM3 offical v3.0.1 code, a.k.a the "Monster merge"
There is a lot of changes, command breaking changes, which is the cause for the JUMP in version number.
It is set to v3.0.0 to show that it is on par with PM3 Offical v3 release.
- Updated 'mkversion.pl' to write a date based on file when repo is downloaded as a zip file from github (iceman)
- Update 'readme.md' to fit GitHubs markup(joanbono)
- Added 'script run ul_uid', try to change UID on a magic UL-card. (iceman)
- Fixed 'hf snoop' bug, of wrong bool value (ikarus23)
- Fixed fullimage.s19, wrong offsets (doegox)
- Updated '77-mm-usb-device-blacklist.rules' for the pid/vid (iceman)
- 'hf 14a sim' now follows Mifare UL-EV1 protocol better (iceman)
- Updated 'fpga_hf.bit' file (piwi)
- Added more card detections to 'hf mfu info' (iceman)
- Fixed 'hf mfu restore/dump' to use the right struct values in special data in dumpfile. (iceman)
- Added 'hf mfu restore r' new parameter to use the new pwd for all further auths needed when executing (iceman)
- Added 'default_keys_dic2lua.awk' script to generate default_keys file in client/lualibs (iceman)
- Fixes to lots of lua scripts, among others
- 'mifare_autopwn', now uses PRNG detection (iceman)
- 'mfkeys', fixed bug which only tested the first key (iceman)
- 'dumptoemul', removed last newline (iceman)
- ...
- Added USB/SERIAL communication enhancements (micolous)
- Change 'hf 14a cuids', to be interrupted with keyboard press (iceman)
- Change debugstatements for LF to show which function more unified (iceman)
- Added 'script run calc_di' , to calculate some Mifare keys (iceman)
- Fixed iclass commands never shut down antenna afterwards (iceman)
- Change 512kb detection when flashing (iceman)
- Fixed compilation GCC4.9 or higher detection (winguru)
- Fixed compiler warnings in Ubuntu 17.04 (iceman)
- Ripped out 'standalone' code into separete folder to be continued. (iceman)
- 'hf mf nested', added key validation to entered key (merlokk)
- 'hf mf hardnested', added key validation to enterd key (iceman)
- Change a lot of help texts (iceman)
- Fixed 'hf mf chk' - keyblock bug, limited keys to 256. (iceman)
- Change 'hf mf dump' retries three times now before giving up (marshmellow)
- Fixed 'mfu authentication', with pack-len error (iceman)
- 'Script list', change sortorder to alphabetic order (iceman)
- Change 'hf mfu gen' to read taguid (iceman)
- Change 'hf mfu pwdgen' to read taguid (iceman)
- Added 'hf mf setmod' sets Mifare Classic EV1 load modulation strength to card (angelsl)
- Added 'hf 14a read' Mifare PRNG detection based on @doegox LIBNFC impl (iceman)
- Added 'hf mf nonces', collects Mifare Classic nonces for analysing of PRNG (iceman)
- Added new CSNS in 'hf iclass sim 2' attack (iceman)
- Added more default keys (iceman)
- Added analyse nuid, enable creation of Mifare NUID (iceman)
- Updated the Reveng 1.44 sourcecode to 1.51 from Reveng project homepage (iceman)
- script run formatMifare - got an option to execute the generate strings (iceman)
- Fix 'hf mf cgetsc' (iceman)
- Fix 'hf legic info' (iceman)
- Change version output (iceman)
- Added PAC/Stanley detection to lf search (marshmellow)
- Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow)
- Added hf mf csave commands compatibity for 4k (Fl0-0)
- Added data fsktonrz, a fsk cleaning/demodulating routine for weak fsk signal. Note: follow this up with a `data rawdemod nr` to finish demoding your signal. (marshmellow)
- Added lf em 410xbrute, LF EM410x reader bruteforce attack by simulating UIDs from a file (Fl0-0)
- Compiles on OS X
- Compiles with gcc 4.9
- Compiles for non-Intel CPUs
- Added lf hitag write 24, the command writes a block to hitag2 tags in crypto mode (henjo)
- Added the improved 'hf mf hardnested', an attack working for hardened Mifare cards (EV1, Mifare Plus SL1)
- Added experimental testmode write option for t55xx (danger) (marshmellow)
- Added t55xx p1detect to `lf search` chip detections (marshmellow)
- Added lf t55xx p1detect, detect page 1 of a t55xx tag based on E015 mfg code (marshmellow)
- Added lf noralsy demod, read, clone, sim commands (iceman)
- Added lf jablotron demod, read, clone, sim commands (iceman)
- Added lf nexwatch read - reads a nexwatch tag from the antenna
- Added lf paradox read - reads a paradox tag from the antenna
- Added lf fdx sim (iceman)
- Added lf fdx clone - clones an fdx-b animal tag to t55x7 or q5 (iceman)
- Added lf fdx read - reads a fdx-b tag from the antenna (iceman)
- Added lf gproxii read - reads a gproxii tag from the antenna (marshmellow)
- Added lf indala read - reads an indala tag from the antenna (marshmellow)
- Added lf visa2000 demod, read, clone, sim commands (iceman)
## [1.7.0 iceman fork] [2017-03-07]
- hf mf dump - added retry loops to try each read attempt up to 3 times. makes getting a complete dump easier with many antennas. (marshmellow)
- Added markers in the graph around found Sequence Terminator after askmandemod. (marshmellow)
- Added data mtrim <start> <stop> command to trim out samples between start and stop. (marshmellow)
- Added data setgraphmarkers <orange> <blue> command to set two extra markers on the graph (marshmellow)
- added json support in lua (vitorio)
- added a buspirate settings file for at91sam7s512 (adamlaurie)
- `lf read` timeouts is now depended on what threshold level you set in `lf config` (marshmellow)
- `hf mf sim` fixed a bug which made sim fail auths. (iceman)
- `hf 14a read` added magic tag generation 1a and 1b detection (iceman)
- correctly using stdtypes.h printf and scanf format string macros (PRIx64 et al) (pwpivi)
- fix linker warning re missing entry point when linking fullimage.elf (pwpivi)
- small changes to lf psk and fsk demods to improve results when the trace begins with noise or the chip isn't broadcasting yet (marshmellow)
- NOTE CHANGED ALL `lf em4x em*` cmds to simpler `lf em ` - example: `lf em4x em410xdemod` is now `lf em 410xdemod`
- Renamed and rebuilt `lf em readword` && readwordpwd to `lf em 4x05read` - it now demods and outputs the read block (marshmellow/iceman)
- Renamed and rebuilt `lf em writeword` && writewordpwd to `lf em 4x05write` - it now also reads validation output from the tag (marshmellow/iceman)
- Fixed bug in lf sim and continuous demods not turning off antenna when finished
- Added lua script path fixes (pwpivi)
- `lf search` - Added EM4x05/EM4x69 chip detection (marshmellow)
- Added lf em 4x05dump command to read and output all the blocks of the chip (marshmellow)
- Added lf em 4x05info command to read and display information about the chip (marshmellow)
- `lf em4x em4x50***` refactoring of em4x50 commands. (iceman)
## [1.6.9 iceman fork] [2017-02-06]
- Serial speedup, if possible 408600baud otherwise default to 115200baud (iceman)
- `hf emv` - Added Peter Fillmore's EMV branch now compiles on iceman fork. See seperate issue. (iceman)
- `hf 14a reader` - Aztek detection. (iceman)
- `standalone mode` - added more detection of tags and refactored (iceman)
- `script run ufodump` - dumps an Aztek tag. (iceman)
- `script run hard_autopwn` - runs hardnested attack against all sectors on tag (iceman)
- Added lf cotag read, and added it to lf search (iceman)
- Added hitag2 read UID only and added that to lf search (marshmellow)
- `lf search` - check for if signal is only noice (marshmellow)
- `hf 14a reader` - fixed a bug when card has sak 0x00 but still is not UL/NTAG etc. (iceman)
- `hf mf sim` / `hf 14a sim` - use random nonce. (micolous)
- `hw tune` - only prints out if voltage is detected from antenna. (iceman)
- `hf iclass decrypt` - only decrypt Application1 (iceman)
- `lf t55xx detect` - when finding multiple possible config blocks, see if a known configblock exists and select. (iceman)
## [1.6.7 iceman fork] [2017-01-05]
- `lf animal` - FDX-B animal commands (iceman)
- Fixed bugs in `lf sim` and other lf continuous demods not turning off antenna when finished (marshmellow)
- `hf iclass write` - fixed bugs, added crc. (?)
- `hf iclass dump` - changed layout in dump (iceman)
- Changed - debug statements are more clear (iceman)
- `lf search` - fixed the silent option when acquire data. (iceman)
- `lf search` - added presco, visa2000, noralsy detection (iceman)
- `lf precso` - fixed some bitsgeneration in precso bits (iceman)
- Added `lf noralsy` - adds demod/clone/sime of Noralsy LF tags. (iceman)
- Added `lf visa2000` - adds demod/clone/sim of Visa2000 lF tags. (iceman)
- Added `hf mf key_brute` - adds J-Runs 2nd phase bruteforce ref: https://github.com/J-Run/mf_key_brute (iceman)
- Added `lf jablotron` - adds demod/clone/sim of Jablotron LF tags. (iceman)
- Added `lf t55xx recoverpw` - adds a new password recovery using bitflips and partial flips if password write went bad. (alexgrin)
- `hf legic` - added improved legic data mapping. (jason)
- `hf mf mifare` - added possibility to target key A|B (douniwan5788)
- Added `analyse lcr` - added a new main command group, to help analysing bytes & bits & nibbles. (iceman)
- Added `lf nedap` - added identification of a NEDAP tag. (iceman)
- `lf viking clone` - fixed a bug. (iceman)
- Added bitsliced bruteforce solver in `hf mf hardnested` (Aczid)
- `hf mf chk` speedup (iceman)
- `hf 14a/mf sim x` attack mode, now uses also moebius version of mfkey32 to try finding the key. (iceman)
- `hf 14a sim` Added emulation of Mifare cards with 10byte UID length. (iceman)
- `hf mf sim` Added emulation of Mifare cards with 10byte UID length. (iceman)
- Added `lf guard clone/sim` (iceman)
- Added `lf pyramd clone/sim` (iceman)
- trying to fix `hf 14b` command to be able to read CALYPSO card. (iceman)
- `hf legic load`, it now loads faster and a casting bug is gone. (iceman)
- Added `hf legic calccrc8` added a method to calculate the legic crc-8 value (iceman)
- `hf legic decode` fixed the output overflow bugs, better printing (iceman)
- Coverity Scan fixes a lot of resource leaks, etc (iceman)
- Added `lf presco *` commands started (iceman)
- Added `lf hid wiegand` added a method to calculate WIEGAND in different formats, (iceman)
- `hf mf chkkeys` better printing, same table output as nested, faster execution and added Adam Lauries "try to read Key B if Key A is found" (iceman)
- `hf mf nested` better printing and added Adam Lauries "try to read Key B if Key A is found" (iceman)
- `hf mf mifare` fixing the zero parity path, which doesn't got called. (iceman)
- Updated the @blapost's Crapto1 implementation to v3.3 (blapost)
- `hf mf c*` updated the calling structure and refactored of the chinese magic commands (iceman, marshmellow)
- Started to add Peter Fillmore's EMV fork into Iceman fork. ref: https://github.com/peterfillmore/proxmark3 (peter fillmore, iceman)
- Added Travis-CI automatic build integration with GitHub fork. (iceman)
- Updated the Reveng 1.30 sourcecode to 1.31 from Reveng project homepage (iceman)
- Updated the Reveng 1.31 sourcecode to 1.40 from Reveng project homepage (iceman)
- Added possibility to write direct to a Legic Prime Tag (MIM256/1024) without using values from the 'BigBuffer' -> 'hf legic writeRaw <addr> <value>' (icsom)
- Added possibility to decrease DCF values at address 0x05 & 0x06 on a Legic Prime Tag
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
load the data into the BigBuffer before with 'hf legic load <path/to/legic.dump>' & then
write the DCF-Values (both at once) with 'hf legic write 0x05 0x02' (icsom)
- Added script `legic.lua` for display and edit Data of Legic-Prime Tags (icsom)
- Added the experimental HITAG_S support (spenneb)
- Added topaz detection to `hf search` (iceman)
- Fixed the silent mode for 14b to be used inside `hf search` (iceman)
### Added
- Added a LF ASK Sequence Terminator detection option to the standard ask demod - and applied it to `lf search u`, `lf t55xx detect`, and `data rawdemod am s` (marshmellow)
- `lf awid bruteforce <facilitycode>` - Simple bruteforce attack against a AWID reader.
- `lf t55xx bruteforce <start password> <end password> [i <*.dic>]` - Simple bruteforce attack to find password - (iceman and others)
- `lf viking clone`- clone viking tag to t55x7 or Q5 from 4byte hex ID input
- `lf viking sim` - sim full viking tag from 4byte hex ID input
- `lf viking read` - read viking tag and output ID
- `lf t55xx wipe` - sets t55xx back to factory defaults
- Added viking demod to `lf search` (marshmellow)
- `data askvikingdemod` demod viking id tag from graphbuffer (marshmellow)
- `lf t55xx resetread` added reset then read command - should allow determining start of stream transmissions (marshmellow)
- `lf t55xx wakeup` added wake with password (AOR) to allow lf search or standard lf read after (iceman, marshmellow)
- `hf mf eload u` added an ultralight/ntag option. (marshmellow)
- `hf iclass managekeys` to save, load and manage iclass keys. (adjusted most commands to accept a loaded key in memory) (marshmellow)
- `hf iclass readblk` to select, authenticate, and read 1 block from an iclass card (marshmellow)
- `hf iclass writeblk` to select, authenticate, and write 1 block to an iclass card (or picopass) (marshmellow + others)
- `hf iclass clone` to take a saved dump file and clone selected blocks to a new tag (marshmellow + others)
- `hf iclass calcnewkey` - to calculate the div_key change to change a key - (experimental) (marshmellow + others)
- `hf iclass encryptblk` - to encrypt a data block hex to prep for writing that block (marshmellow)
- ISO14443a stand-alone operation with ARM CFLAG="WITH_ISO14443a_StandAlone". This code can read & emulate two banks of 14a tag UIDs and write to "magic" cards (Craig Young)
- AWID26 command context added as 'lf awid' containing realtime demodulation as well as cloning/simulation based on tag numbers (Craig Young)
- Added 'hw status'. This command makes the ARM print out some runtime information. (holiman)
- Added 'hw ping'. This command just sends a usb packets and checks if the pm3 is responsive. Can be used to abort certain operations which supports abort over usb. (holiman)
- Added `data hex2bin` and `data bin2hex` for command line conversion between binary and hexadecimal (holiman)
- Added 'hf snoop'. This command take digitalized signal from FPGA and put in BigBuffer. (pwpiwi + enio)
- Added Topaz (NFC type 1) protocol support ('hf topaz reader', 'hf list topaz', 'hf 14a raw -T', 'hf topaz snoop'). (piwi)
- Added option c to 'hf list' (mark CRC bytes) (piwi)
### Changed
- Added `[l] <length>` option to data printdemodbuffer
- Adjusted lf awid clone to optionally clone to Q5 tags
- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7
- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal)
- Adjusted lf pskindalademod to reduce false positive reads.
- Small adjustments to psk, nrz, and ask clock detect routines - more reliable.
- Adjusted lf em410x em410xsim to accept a clock argument
- Adjusted lf t55xx dump to allow overriding the safety check and warning text (marshmellow)
- Adjusted lf t55xx write input variables (marshmellow)
- Adjusted lf t55xx read with password safety check and warning text and adjusted the input variables (marshmellow & iceman)
- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. (marshmellow)
- Adjusted timings for t55xx commands. more reliable now. (marshmellow & iceman)
- `lf cmdread` adjusted input methods and added help text (marshmellow & iceman)
- changed `lf config t <threshold>` to be 0 - 128 and will trigger on + or - threshold value (marshmellow)
- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) (marshmellow)
- Revised workflow for StandAloneMode14a (Craig Young)
- EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers)
- 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi)
- Added `r` option to iclass functions - allows key to be provided in raw block 3/4 format
## [2.2.0][2015-07-12]
### Changed
- Added `hf 14b raw -s` option to auto select a 14b std tag before raw command
- Changed `hf 14b write` to `hf 14b sriwrite` as it only applied to sri tags (marshmellow)
- Added `hf 14b info` to `hf search` (marshmellow)
- Added compression of fpga config and data, *BOOTROM REFLASH REQUIRED* (piwi)
- Implemented better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (piwi)
### Added
- Add `hf 14b reader` to find and print general info about known 14b tags (marshmellow)
- Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (marshmellow)
- Add PACE replay functionality (frederikmoellers)
### Fixed
- t55xx write timing (marshmellow)
## [2.1.0][2015-06-23]
### Changed
- Added ultralight/ntag tag type detection to `hf 14a read` (marshmellow)
- Improved ultralight dump command to auto detect tag type, take authentication, and dump full memory (or subset specified) of known tag types (iceman1001 / marshmellow)
- Combined ultralight read/write commands and added authentication (iceman1001)
- Improved LF manchester and biphase demodulation and ask clock detection especially for reads with heavy clipping. (marshmellow)
- Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman)
- *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi)
### Fixed
- Fixed EM4x50 read/demod of the tags broadcasted memory blocks. 'lf em4x em4x50read' (not page read) (marshmellow)
- Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow)
- Fixed various problems with iso14443b, issue #103 (piwi, marshmellow)
### Added
- Added `hf search` - currently tests for 14443a tags, iclass tags, and 15693 tags (marshmellow)
- Added `hf mfu info` Ultralight/NTAG info command - reads tag configuration and info, allows authentication if needed (iceman1001, marshmellow)
- Added Mifare Ultralight C and Ultralight EV1/NTAG authentication. (iceman1001)
- Added changelog
- Added `data fdxbdemod` - Demodulate a FDX-B ISO11784/85 Biphase tag from GraphBuffer aka ANIMAL TAG (marshmellow, iceman1001)
## [2.0.0] - 2015-03-25
### Changed
- LF sim operations now abort when new commands arrive over the USB - not required to push the device button anymore.
### Fixed
- Mifare simulation, `hf mf sim` (was broken a long time) (pwpiwi)
- Major improvements in LF area and data operations. (marshmellow, iceman1001)
- Issues regarding LF simulation (pwpiwi)
### Added
- iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers don't seem to enforce update. (holiman).
- iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode.

View file

@ -1,12 +1,13 @@
The project compiles on Linux, Mac OS X and Windows (MinGW/MSYS).
it requires:
- gcc >= 4.4
- gcc >= 4.8
- libpthread
- libreadline
- libusb
- perl
- an ARM cross-compiler to compile the firmware
- libncurses5-dev
and optionally QT for the GUI
@ -16,7 +17,22 @@ To compile, just run "make".
===========
= Windows =
===========
The following is a complete list of packages required to setup the compile environment yourself. Alternatively you can download an archive of the full environment (see below).
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
Afterwards just clone the iceman repo or download someone elses. Read instructions on @Gator96100 repo page. (https://github.com/Gator96100/ProxSpace/)
Download the ProxSpace environment archive and extract it to C:\
Links
https://github.com/Gator96100/ProxSpace/archive/master.zip
-- OR --
Use the following list of packages required to setup the compile environment yourself.
1 - Install QT SDK for Windows [1]
@ -71,17 +87,80 @@ Download links:
[5] http://sourceforge.net/projects/devkitpro/files/Automated%20Installer/devkitProUpdater-1.5.0.exe/download
[6] http://strawberry-perl.googlecode.com/files/strawberry-perl-5.10.1.1.msi
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 http://code.google.com/p/proxmark3/downloads/list
Download the ProxSpace environment archive and extract it to C:\
============
= Mac OS X =
============
macport stuff should do ;)
Installing from HomeBrew tap
---------------------------
This method is recommended and tested on macOS Sierra 10.12.3
1. Install homebrew if you haven't yet already done so: http://brew.sh/
2. Tap proxmark repo:
brew tap iceman1001/proxmark3
3. Install Proxmark3:
Stable release
brew install proxmark3
Latest non-stable from GitHub (use this if previous command fails)
brew install --HEAD proxmark3
For more information go to https://github.com/iceman1001/homebrew-proxmark3
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 Sierra 10.12.6
*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 iceman1001/proxmark3/proxmark3`
2. Flash the bootloader
* With your Proxmark3 unplugged from your machine, press and hold the button on your Proxmark 3 as you plug it into a USB port. After about 5 seconds let go of the button and run this command
`$ sudo proxmark3-flasher /dev/tty.usbmodem881 /usr/local/Cellar/proxmark3/HEAD-ccfdd60/share/firmware/fullimage.elf`
* After the bootloader finishes flashing, unplug your Proxmark3 from your machine
3. Flash fullimage.elf
* Press and hold the button on your Proxmark 3 and keep it held as you plug the Proxmark 3 back into the 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 /usr/local/Cellar/proxmark3/HEAD-ccfdd60/share/firmware/fullimage.elf`
4. Enjoy the update
Compilling from source manually (Legacy)
---------------------------
Tested on OSX 10.10 Yosemite
1 - Install Xcode and Xcode Command Line Tools
2 - Install Homebrew and dependencies
brew install readline libusb p7zip libusb-compat wget qt5 pkgconfig
3 - Download DevKitARM for OSX
http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/
Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory.
4 - Edit proxmark3/client/Makefile adding path to readline and qt5
LDLIBS = -L/usr/local/opt/readline/lib -L/usr/local/opt/qt5/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm
CFLAGS = -std=c99 -I/usr/local/opt/qt5/include -I/usr/local/opt/readline/include -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
If your old brew intallation use /usr/local/Cellar/ path replace /usr/local/opt/readline/lib with your actuall readline and qt5 path. See homebrew manuals.
5 - Set Environment
export DEVKITPRO=$HOME/proxmark3/
export DEVKITARM=$DEVKITPRO/devkitARM
export PATH=${PATH}:${DEVKITARM}/bin
============
= Linux =

View file

@ -1,10 +1,34 @@
include common/Makefile.common
GZIP=gzip
# Windows' echo echos its input verbatim, on Posix there is some
# amount of shell command line parsing going on. echo "" on
# Windows yields literal "", on Linux yields an empty line
ifeq ($(shell echo ""),)
# This is probably a proper system, so we can use uname
DELETE=rm -rf
FLASH_TOOL=client/flasher
platform=$(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
FLASH_PORT=com3
PATHSEP=\\#
else
FLASH_PORT=/dev/ttyACM0
PATHSEP=/
endif
else
# Assume that we are running on native Windows
DELETE=del /q
FLASH_TOOL=client/flasher.exe
platform=Windows
FLASH_PORT=com3
PATHSEP=\\#
endif
all clean: %: bootrom/% armsrc/% client/% recovery/%
all clean: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/%
mfkey/%: FORCE
$(MAKE) -C tools/mfkey $(patsubst mfkey/%,%,$@)
nonce2key/%: FORCE
$(MAKE) -C tools/nonce2key $(patsubst nonce2key/%,%,$@)
bootrom/%: FORCE
$(MAKE) -C bootrom $(patsubst bootrom/%,%,$@)
armsrc/%: FORCE
@ -15,35 +39,29 @@ recovery/%: FORCE
$(MAKE) -C recovery $(patsubst recovery/%,%,$@)
FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites)
.PHONY: all clean help _test flash-bootrom flash-os flash-all FORCE
.PHONY: all clean help _test flash-bootrom flash-os flash-fpga flash-both flash-all FORCE
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:
@echo + all - Make bootrom, armsrc and the OS-specific host directory
@echo + client - Make only the OS-specific host directory
@echo + flash-bootrom - Make bootrom and flash it
@echo + flash-os - Make armsrc and flash os
@echo + flash-fpga - Make armsrc and flash fpga
@echo + flash-both - Make armsrc and flash os and fpga image
@echo + flash-all - Make bootrom and armsrc and flash bootrom, os and fpga image
@echo + 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
client: client/all
flash-bootrom: bootrom/obj/bootrom.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$<)
flash-os: armsrc/obj/osimage.elf $(FLASH_TOOL)
flash-os: armsrc/obj/fullimage.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<)
flash-fpga: armsrc/obj/fpgaimage.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<)
flash-both: armsrc/obj/osimage.elf armsrc/obj/fpgaimage.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^))
flash-all: bootrom/obj/bootrom.elf armsrc/obj/osimage.elf armsrc/obj/fpgaimage.elf $(FLASH_TOOL)
flash-all: bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^))
newtarbin:
@ -53,5 +71,22 @@ newtarbin:
tarbin: newtarbin client/tarbin armsrc/tarbin bootrom/tarbin
$(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
udev:
sudo cp -rf driver/77-mm-usb-device-blacklist.rules /etc/udev/rules.d/77-mm-usb-device-blacklist.rules
sudo udevadm control --reload-rules
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 $* = $($*)
# Dummy target to test for GNU make availability
_test:

225
README.md Normal file
View file

@ -0,0 +1,225 @@
Iceman fork
===============
[![Build Status](https://travis-ci.org/iceman1001/proxmark3.svg?branch=master)](https://travis-ci.org/iceman1001/proxmark3)[![Coverity Status](https://scan.coverity.com/projects/5117/badge.svg)](https://scan.coverity.com/project/proxmark3_iceman_fork)[![Latest release](https://img.shields.io/github/release/iceman1001/proxmark3.svg)](https://github.com/iceman1001/proxmark3/releases/latest)
## This fork is HIGHLY experimental and bleeding edge
The kickstarter for the latest revision of proxmark is out.
[proxmark3 rdv4.0](https://www.kickstarter.com/projects/1408815241/proxmark3-rdv-40)
That one is a beauty!
## Nothing says thank you as much as a donation
https://paypal.me/iceman1001/ Feel free to donate. All support is welcome.
monereo: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP
## Notice
There is so much in this fork, with all fixes and additions its basically the most enhanced fork to this day for the Proxmark3 device. Which makes it so awesum to play with. Do please play with it. Get excited and experiment. As a side note with all coverity scan fixes this client is much more stable than PM3 Master even if I tend to break it sometimes. I'll try to make a release when this fork becomes stable between my experiments.
## 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:
- Configure
`cov-configure --comptype gcc --compiler /opt/devkitpro/devkitARM/bin/arm-none-eabi-gcc`
- Run it (I'm running on Ubuntu)
`cov-build --dir cov-int make all`
- Make a tarball
`tar czvf proxmark3.tgz cov-int`
- Upload it to coverity.com
## Whats changed?
Whats so special with this fork? I have scraped the web for different enhancements to the PM3 source code and not all of them ever found their way to the master branch.
Among the stuff is
* Jonor's hf 14a raw timing patch
* Piwi's updates. (usually gets into the master)
* Piwi's "topaz" branch
* Piwi's "hardnested" branch
* Holiman's iclass, (usually gets into the master)
* Marshmellow's fixes (usually gets into the master)
* Midnitesnake's Ultralight, Ultralight-c enhancements
* Izsh's lf peak modification / iir-filtering
* Aspers's tips and tricks from inside the PM3-gui-tool, settings.xml and other stuff.
* My own desfire, Ultralight extras, LF T55xx enhancements, bugs fixes (filelength, hf mf commands ), TNP3xxx lua scripts, Awid26, skidata scripts (will come)
* other obscure patches like for the sammy-mode, (offline you know), tagidentifications, defaultkeys.
* Minor textual changes here and there.
* Simulation of Ultralight/Ntag.
* Marshmellow's and my "RevEng" addon for the client. Ref: http://reveng.sourceforge.net/ Now using reveng1.44
* J-Run alternative bruteforce Mifare nested auths.. (you need one other exe to make it work)
* A Bruteforce for T55XX passwords against tag.
* A Bruteforce for AWID 26, starting w a facilitycode then trying all 0xFFFF cardnumbers via simulation. To be used against a AWID Reader.
* A Bruteforce for HID, starting w a facilitycode then trying all 0xFFFF cardnumbers via simulation. To be used against a HID Reader.
* Blaposts Crapto1 v3.3
* Icsom's legic script and legic enhancements
* Aczid's bitsliced bruteforce solver in 'hf mf hardnested'
---
## Why don't you merged with offical PM3 Master?
Me fiddling with the code so much, there is a nightmare in merging a PR. I will never find time to do PR because of it. Much of what you find here is not in the interest for offical PM3. However and luckily I have @marshmellow42 who takes some stuff and push PR's back. The separation from offical pm3 repo gives me very much freedom to create a firmware/client in the way I want to use the PM3.
## Why don't you add this or that functionality?
Give me a hint, and I'll see if I can't merge in the stuff you have.
## PM3 GUI
I do tend to rename and move stuff around, the official PM3-GUI from Gaucho will not work so well. *sorry*
## Development
This fork now compiles just fine on
- Windows/mingw environment with Qt5.6.1 & GCC 4.8
- Ubuntu 1404, 1510, 1604
- Mac OS X / Homebrew
- 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
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/iceman1001/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 iceman fork
`git clone https://github.com/iceman1001/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 iceman fork
`git clone https://github.com/iceman1001/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 iceman1001/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 iceman1001/proxmark3/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`
`$ sudo proxmark3-flasher /dev/tty.usbmodem881 `
4. Enjoy the update
## Docker container
I recently added a docker container on Docker HUB. You find it here: https://hub.docker.com/r/iceman1001/proxmark3/
Follow those instructions to get it up and running. No need for the old proxspace-environment anymore.
-[1.6.0] How to start: https://www.youtube.com/watch?v=b5Zta89Cf6Q
-[1.6.0] How to connect: https://youtu.be/0ZS2t5C-caI
-[1.6.1] How to flash: https://www.youtube.com/watch?v=WXouhuGYEiw
Recommendations: Use only latest container.
## Building on Windows
### 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
Afterwards just clone the iceman repo or download someone elses.
Read instructions on @Gator96100 repo page. (https://github.com/Gator96100/ProxSpace/)
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)
- https://github.com/Gator96100/ProxSpace/releases/tag/v2.1 (release v2.1 with gcc v5.3.0)
### 7. Build and run
- Clone iceman fork
`git clone https://github.com/iceman1001/proxmark3.git`
- Get the latest commits
`git pull`
- 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
January 2015, Sweden

View file

@ -1,88 +0,0 @@
NOTICE:
(2014-03-26)
This is now the official Proxmark repository!
INTRODUCTION:
The proxmark3 is a powerful general purpose RFID tool, the size of a deck
of cards, designed to snoop, listen and emulate everything from
Low Frequency (125kHz) to High Frequency (13.56MHz) tags.
This repository contains enough software, logic (for the FPGA), and design
documentation for the hardware that you could, at least in theory,
do something useful with a proxmark3.
RESOURCES:
* This repository!
https://github.com/Proxmark/proxmark3
* The Wiki
https://github.com/Proxmark/proxmark3/wiki
* The GitHub page
http://proxmark.github.io/proxmark3/
* The Forum
http://www.proxmark.org/forum
* The IRC chanel
irc.freenode.org #proxmark3
-or-
http://webchat.freenode.net/?channels=#proxmark3
DEVELOPMENT:
The tools required to build or run the project will vary depending on
your operating system. Please refer to the Wiki for details.
* https://github.com/Proxmark/proxmark3/wiki
OBTAINING HARDWARE:
The Proxmark 3 is available for purcahse (assembled and tested) from the
following locations:
* http://proxmark3.com/
* http://www.xfpga.com/
Most of the ultra-low-volume contract assemblers could put
something like this together with a reasonable yield. A run of around
a dozen units is probably cost-effective. The BOM includes (possibly-
outdated) component pricing, and everything is available from Digikey
and the usual distributors.
If you've never assembled a modern circuit board by hand, then this is
not a good place to start. Some of the components (e.g. the crystals)
must not be assembled with a soldering iron, and require hot air.
The schematics are included; the component values given are not
necessarily correct for all situations, but it should be possible to do
nearly anything you would want with appropriate population options.
The printed circuit board artwork is also available, as Gerbers and an
Excellon drill file.
LICENSING:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Jonathan Westhues
user jwesthues, at host cq.cx
May 2007, Cambridge MA

290
appveyor.yml Normal file
View file

@ -0,0 +1,290 @@
version: 3.0.1.{build}
image: Visual Studio 2017
clone_folder: C:\ProxSpace\pm3
init:
- ps: >-
$psversiontable
#Get-ChildItem Env:
$releasename=""
$env:APPVEYOR_REPO_COMMIT_SHORT = $env:APPVEYOR_REPO_COMMIT.Substring(0, 8)
if ($env:appveyor_repo_tag -match "true"){
$releasename=$env:APPVEYOR_REPO_TAG_NAME + "/"
}
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]"
Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow
Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename"
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
clone_script:
- ps: >-
Write-Host "Removing ProxSpace..." -NoNewLine
cd \
Remove-Item -Recurse -Force -Path c:\ProxSpace\*
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Git clone ProxSpace..." -NoNewLine
git clone -q https://github.com/Gator96100/ProxSpace c:\ProxSpace
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Removing pm3 dir..." -NoNewLine
Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\*
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine
if(-not $env:appveyor_pull_request_number) {
git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
cd $env:appveyor_build_folder
git checkout -qf $env:appveyor_repo_commit
} else {
git clone -q https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
cd $env:appveyor_build_folder
git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge:
git checkout -qf FETCH_HEAD
}
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Fill msys\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"
Write-Host "[ OK ]" -ForegroundColor Green
install:
- ps: >-
function Exec-External {
param(
[Parameter(Position=0,Mandatory=1)][scriptblock] $command
)
& $command
if ($LASTEXITCODE -ne 0) {
throw ("Command returned non-zero error-code ${LASTEXITCODE}: $command")
}
}
build_script:
- ps: >-
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
#make
bash -lc -i "pwd;make all"
#some checks
if(!(Test-Path C:\ProxSpace\pm3\client\proxmark3.exe)){
throw "Main file proxmark3.exe not exists."
}
if(!(Test-Path C:\ProxSpace\pm3\armsrc\obj\fullimage.elf)){
throw "ARM file fullimage.elf not exists."
}
if(!(Test-Path C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z)){
throw "Files in hardnested\tables not exists."
}
#copy
Write-Host "Copy release files..." -NoNewLine -ForegroundColor Yellow
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release
Copy-Item C:\ProxSpace\pm3\client\*.exe C:\ProxSpace\Release
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\arm
Copy-Item C:\ProxSpace\pm3\armsrc\obj\*.elf C:\ProxSpace\Release\arm
Copy-Item C:\ProxSpace\pm3\bootrom\obj\*.elf C:\ProxSpace\Release\arm
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\scripts
Copy-Item C:\ProxSpace\pm3\client\scripts\*.lua C:\ProxSpace\Release\scripts
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\hardnested\tables
Copy-Item C:\ProxSpace\pm3\client\hardnested\*.bin C:\ProxSpace\Release\hardnested
Copy-Item C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z C:\ProxSpace\Release\hardnested\tables
Write-Host "[ OK ]" -ForegroundColor Green
#archive and push
$releasename=""
if ($env:appveyor_repo_tag -match "true"){
$releasename=$env:APPVEYOR_REPO_TAG_NAME + "/"
}
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT.Substring(0, 7) + "]"
Write-Host "Archive and publish release files ($releasename)..." -NoNewLine -ForegroundColor Yellow
cd C:\ProxSpace
7z a release.zip C:\ProxSpace\Release
Push-AppveyorArtifact release.zip -DeploymentName "$releasename"
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Builded..." -ForegroundColor Yellow
test_script:
- ps: >-
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
cd c:\ProxSpace\pm3
$global:TestsPassed=$true
Function ExecTest($Name, $File, $Cmd, $CheckResult) {
#--- begin Job
$Job = Start-Job -ScriptBlock {
[bool]$res=$false
$TestTime=[System.Environment]::TickCount
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
Set-Location $using:PWD
$sb=[scriptblock]::Create("$using:Cmd")
#execute scriptblock
Write-host "Test [$using:Name] job: $using:Cmd"
$Cond=&$sb
if ($Cond -eq $null){
} ElseIf($using:CheckResult -ne $null) {
[String]$searchstr=""
if ($Cond -is [Object]){
ForEach($line in $Cond){
Write-host $line -ForegroundColor Gray
$searchstr += $line
}
}else{
Write-host "$Cond" -ForegroundColor Gray
$searchstr = $Cond
}
If($searchstr -like "*$using:CheckResult*") {
$res=$true
}
$Cond="*$using:CheckResult*"
} Else {
If (!($Cond -is [bool] -or $Cond -is [byte] -or $Cond -is [int16] -or $Cond -is [int32] -or $Cond -is [int64] -or $Cond -is [float])){
if ($Cond -is "String" -and $Cond -like "*passed*"){
$res= $true
}
if ($Cond -is "String" -and $Cond -like "*true*"){
$res= $true
}
} Else {
$res=$Cond
}
}
If ($res) {
Write-host "Result[$using:Name]: $Cond" -ForegroundColor Green
Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
}Else {
Write-host "Result[$using:Name]: $Cond" -ForegroundColor Red
Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" -ErrorMessage "command:$using:Cmd`nresult:$Cond"
}
return $res
}
#--- end Job
[bool]$res=$false
# Wait 60 sec timeout for Job
if(Wait-Job $Job -Timeout 60){
$Results = $Job | Receive-Job
if($Results -like "true"){
$res=$true
}
} else {
Write-host "Test [$Name] timeout" -ForegroundColor Red
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 60000 -ErrorMessage "timeout"
}
Remove-Job -Force $Job
if(!$res){
$global:TestsPassed=$false
}
}
Write-Host "Running tests..." -ForegroundColor Yellow
#file test
ExecTest "proxmark3 exists" "proxmark3.exe" {Test-Path C:\ProxSpace\Release\proxmark3.exe}
ExecTest "arm image exists" "\arm\fullimage1.elf" {Test-Path C:\ProxSpace\Release\arm\fullimage.elf}
ExecTest "bootrom exists" "bootrom.elf" {Test-Path C:\ProxSpace\Release\arm\bootrom.elf}
ExecTest "hardnested tables exists" "hardnested" {Test-Path C:\ProxSpace\Release\hardnested\tables\*.z}
ExecTest "release exists" "release.zip" {Test-Path C:\ProxSpace\release.zip}
#proxmark logic tests
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q Execute && echo Passed || echo Failed'}
ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'}
ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf'"} "at_enc"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:"
if ($global:TestsPassed) {
Write-Host "Tests [ OK ]" -ForegroundColor Green
} else {
Write-Host "Tests [ ERROR ]" -ForegroundColor Red
throw "Tests error."
}
on_success:
- ps: Write-Host "Build success..." -ForegroundColor Green
on_failure:
- ps: Write-Host "Build error." -ForegroundColor Red
on_finish:
- ps: $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

266
armsrc/BigBuf.c Normal file
View file

@ -0,0 +1,266 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Aug 2005
// Gerhard de Koning Gans, April 2008, May 2011
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// BigBuf and functions to allocate/free parts of it.
//-----------------------------------------------------------------------------
#include "BigBuf.h"
// BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces.
// Also used to hold various smaller buffers and the Mifare Emulator Memory.
// declare it as uint32_t to achieve alignment to 4 Byte boundary
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
*/
// High memory mark
static uint16_t BigBuf_hi = BIGBUF_SIZE;
// pointer to the emulator memory.
static uint8_t *emulator_memory = NULL;
// trace related variables
static uint16_t traceLen = 0;
int tracing = 1; //Last global one.. todo static?
// get the address of BigBuf
uint8_t *BigBuf_get_addr(void)
{
return (uint8_t *)BigBuf;
}
// get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done
uint8_t *BigBuf_get_EM_addr(void)
{
// not yet allocated
if (emulator_memory == NULL)
emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE);
return emulator_memory;
}
// clear ALL of BigBuf
void BigBuf_Clear(void)
{
BigBuf_Clear_ext(true);
}
// clear ALL of BigBuf
void BigBuf_Clear_ext(bool verbose)
{
memset(BigBuf, 0, BIGBUF_SIZE);
if (verbose)
Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE);
}
void BigBuf_Clear_EM(void){
memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE);
}
void BigBuf_Clear_keep_EM(void)
{
memset(BigBuf, 0, BigBuf_hi);
}
// allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory
// at the beginning of BigBuf is always for traces/samples
uint8_t *BigBuf_malloc(uint16_t chunksize)
{
if (BigBuf_hi - chunksize < 0) {
return NULL; // no memory left
} else {
chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4
BigBuf_hi -= chunksize; // aligned to 4 Byte boundary
return (uint8_t *)BigBuf + BigBuf_hi;
}
}
// free ALL allocated chunks. The whole BigBuf is available for traces or samples again.
void BigBuf_free(void)
{
BigBuf_hi = BIGBUF_SIZE;
emulator_memory = NULL;
// 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?
}
void BigBuf_print_status(void)
{
Dbprintf("Memory");
Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE);
Dbprintf(" Available memory........%d", BigBuf_hi);
Dbprintf("Tracing");
Dbprintf(" tracing ................%d", tracing);
Dbprintf(" traceLen ...............%d", traceLen);
}
// return the maximum trace length (i.e. the unallocated size of BigBuf)
uint16_t BigBuf_max_traceLen(void)
{
return BigBuf_hi;
}
void clear_trace() {
traceLen = 0;
}
void set_tracelen(uint16_t value) {
traceLen = value;
}
void set_tracing(bool enable) {
tracing = enable;
}
bool get_tracing(void) {
return tracing;
}
/**
* Get the number of bytes traced
* @return
*/
uint16_t BigBuf_get_traceLen(void)
{
return traceLen;
}
/**
This is a function to store traces. All protocols can use this generic tracer-function.
The traces produced by calling this function can be fetched on the client-side
by 'hf list raw', alternatively 'hf list <proto>' for protocol-specific
annotation of commands/responses.
**/
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag)
{
if (!tracing) return false;
uint8_t *trace = BigBuf_get_addr();
uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
uint16_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)
// timestamp (start)
trace[traceLen++] = ((timestamp_start >> 0) & 0xff);
trace[traceLen++] = ((timestamp_start >> 8) & 0xff);
trace[traceLen++] = ((timestamp_start >> 16) & 0xff);
trace[traceLen++] = ((timestamp_start >> 24) & 0xff);
// duration
trace[traceLen++] = ((duration >> 0) & 0xff);
trace[traceLen++] = ((duration >> 8) & 0xff);
// data length
trace[traceLen++] = ((iLen >> 0) & 0xff);
trace[traceLen++] = ((iLen >> 8) & 0xff);
// readerToTag flag
if (!readerToTag) {
trace[traceLen - 1] |= 0x80;
}
// data bytes
if (btBytes != NULL && iLen != 0) {
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;
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;
}
// Emulator memory
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){
uint8_t* mem = BigBuf_get_EM_addr();
if(offset+length < CARD_MEMORY_SIZE) {
memcpy(mem+offset, data, length);
return 0;
} else {
Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset+length), CARD_MEMORY_SIZE);
return 1;
}
}

47
armsrc/BigBuf.h Normal file
View file

@ -0,0 +1,47 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Aug 2005
// Gerhard de Koning Gans, April 2008, May 2011
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// BigBuf and functions to allocate/free parts of it.
//-----------------------------------------------------------------------------
#ifndef __BIGBUF_H
#define __BIGBUF_H
#include <stdbool.h> // for bool
#include "proxmark3.h"
#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?!?
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);
#endif /* __BIGBUF_H */

View file

@ -5,11 +5,7 @@
//-----------------------------------------------------------------------------
// LCD code
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "LCD.h"
#include "fonts.h"
void LCDSend(unsigned int data)
{

View file

@ -9,6 +9,10 @@
#ifndef __LCD_H
#define __LCD_H
#include "proxmark3.h"
#include "apps.h"
#include "fonts.h"
// The resolution of the LCD
#define LCD_XRES 132
#define LCD_YRES 132

View file

@ -9,82 +9,179 @@
APP_INCLUDES = apps.h
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation
APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG
#-DWITH_LCD
#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 \
-fno-strict-aliasing -ffunction-sections -fdata-sections
#SRC_LCD = fonts.c LCD.c
SRC_LF = lfops.c hitag2.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
SRC_ISO14443b = iso14443.c
SRC_CRAPTO1 = crapto1.c crypto1.c
### 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
THUMBSRC = start.c \
$(SRC_LCD) \
$(SRC_ISO15693) \
$(SRC_LF) \
appmain.c printf.c \
util.c \
string.c \
usb_cdc.c \
cmd.c
# These are to be compiled in ARM mode
ARMSRC = fpgaloader.c \
legicrf.c \
iso14443crc.c \
crc16.c \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
legic_prng.c \
iclass.c \
crc.c
SRC_LCD = fonts.c LCD.c
SRC_LF = lfops.c hitag2.c hitagS.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_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_ICLASS = iclass.c optimized_cipher.c
SRC_LEGIC = legicrf.c legic_prng.c
SRC_FLASH = flashmem.c
SRC_SMARTCARD = i2c.c
#SRC_FPC = usart.c
SRC_BEE = bee.c
#the FPGA bitstream files. Note: order matters!
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
#the zlib source files required for decompressing the fpga config at run time
SRC_ZLIB = inflate.c inffast.c inftrees.c adler32.c zutil.c
#additional defines required to compile zlib
ZLIB_CFLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED
APP_CFLAGS += $(ZLIB_CFLAGS)
# zlib includes:
APP_CFLAGS += -I../zlib
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS += -I.
# 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
# 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) \
parity.c \
usb_cdc.c \
cmd.c \
lf_samyrun.c \
vtsend.c
# lf_samyrun.c \
# lf_hidbrute.c \
# lf_proxbrute.c \
# hf_mattyrun.c \
VERSIONSRC = version.c \
fpga_version_info.c
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common
OBJS = $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19
COMMON_FLAGS = -Os
OBJS = $(OBJDIR)/fullimage.s19
FPGA_COMPRESSOR = ../client/fpga_compress
all: $(OBJS)
$(OBJDIR)/fpga_lf.o: fpga_lf.bit
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_lf_bit_start=_binary_fpga_lf_bit_start --redefine-sym _binary____fpga_fpga_lf_bit_end=_binary_fpga_lf_bit_end --prefix-sections=fpga_lf_bit $^ $@
.DELETE_ON_ERROR:
$(OBJDIR)/fpga_hf.o: fpga_hf.bit
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_hf_bit_start=_binary_fpga_hf_bit_start --redefine-sym _binary____fpga_fpga_hf_bit_end=_binary_fpga_hf_bit_end --prefix-sections=fpga_hf_bit $^ $@
# version.c should be remade on every compilation
.PHONY: version.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_lf.o $(OBJDIR)/fpga_hf.o $(THUMBOBJ) $(ARMOBJ)
fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@
$(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@
$(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
$(FPGA_COMPRESSOR):
make -C ../client $(notdir $(FPGA_COMPRESSOR))
$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf
$(OBJCOPY) -F elf32-littlearm --only-section .fpgaimage $^ $@
$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf
$(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 $^ $@
$(OBJDIR)/osimage.elf: $(OBJDIR)/fullimage.elf
$(OBJCOPY) -F elf32-littlearm --remove-section .fpgaimage $^ $@
$(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf
$(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@
$(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) $(filter %.bin,$^) $@
$(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@
$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^
tarbin: $(OBJS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf)
clean:
$(DELETE) $(OBJDIR)$(PATHSEP)*.o
$(DELETE) $(OBJDIR)$(PATHSEP)*.elf
$(DELETE) $(OBJDIR)$(PATHSEP)*.s19
$(DELETE) $(OBJDIR)$(PATHSEP)*.map
$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(DELETE) $(OBJDIR)$(PATHSEP)*.z
$(DELETE) $(OBJDIR)$(PATHSEP)*.bin
$(DELETE) version.c
.PHONY: all clean help
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:
@echo + all - Make both:
@echo + $(OBJDIR)/osimage.s19 - The OS image
@echo + $(OBJDIR)/fpgaimage.s19 - The FPGA image
@echo + all - Build the full image $(OBJDIR)/fullimage.s19
@echo + clean - Clean $(OBJDIR)

View file

@ -0,0 +1,999 @@
//-----------------------------------------------------------------------------
// Colin Brigato, 2016,2017
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for HF Mifare aka ColinRun by Colin Brigato
//-----------------------------------------------------------------------------
#include "hf_colin.h"
#define MF1KSZ 1024
#define MF1KSZSIZE 64
//#define FALSE false
//#define TRUE true
#define AUTHENTICATION_TIMEOUT 848
uint8_t cjuid[10];
uint32_t cjcuid;
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
// 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);
uint8_t totalchunks = len / chunksize;
uint8_t last_chunksize = len - (totalchunks * chunksize);
char chunk[chunksize + 1];
memset(chunk, 0x00, sizeof(chunk));
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++) {
memset(chunk, 0x00, sizeof(chunk));
memcpy(chunk, &bigar[i * chunksize], chunksize);
DbprintfEx(FLAG_RAWPRINT, "%s", chunk);
}
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, " ");
}
}
void cjSetCursFRight() {
vtsend_cursor_position(NULL, 98, (currfline));
currfline++;
}
void cjSetCursRight() {
vtsend_cursor_position(NULL, 59, (currline));
currline++;
}
void cjSetCursLeft() {
vtsend_cursor_position(NULL, 0, (curlline));
curlline++;
}
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);
}
void RunMod() {
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.
/* 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
//----------------------------
#define STKEYS 37
const uint64_t mfKeys[STKEYS] = {
0xffffffffffff, // TRANSPORTS
0x000000000000, // Blankkey
0x484558414354, // INFINEONON A / 0F SEC B / INTRATONE / HEXACT...
0x414c41524f4e, // ALARON NORALSY
0x424c41524f4e, // BLARON NORALSY
0x4a6352684677, // COMELIT A General Key / 08 [2] 004
0x536653644c65, // COMELIT B General Key / 08 [2] 004
0x8829da9daf76, // URMET CAPTIV IF A => ALL A/B / BTICINO
0x314B49474956, // "1KIGIV" VIGIK'S SERVICE BADGE A KEY
0xa0a1a2a3a4a5, // PUBLIC BLOC0 BTICINO MAD ACCESS
0x021209197591, // BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
0x010203040506, // VIGIK's B Derivative
0xb0b1b2b3b4b5, // NA DERIVATE B # 1
0xaabbccddeeff, // NA DERIVATE B # 1
0x4d3a99c351dd, // NA DERIVATE B # 1
0x1a982c7e459a, // NA DERIVATE B # 1
0xd3f7d3f7d3f7, // NA DERIVATE B # 1
0x714c5c886e97, // NA DERIVATE B # 1
0x587ee5f9350f, // NA DERIVATE B # 1
0xa0478cc39091, // NA DERIVATE B # 1
0x533cb6c723f6, // NA DERIVATE B # 1
0x8fd0a4f256e9, // NA DERIVATE B # 1
0xa22ae129c013, // INFINEON B 00
0x49fae4e3849f, // INFINEON B 01
0x38fcf33072e0, // INFINEON B 02
0x8ad5517b4b18, // INFINEON B 03
0x509359f131b1, // INFINEON B 04
0x6c78928e1317, // INFINEON B 05
0xaa0720018738, // INFINEON B 06
0xa6cac2886412, // INFINEON B 07
0x62d0c424ed8e, // INFINEON B 08
0xe64a986a5d94, // INFINEON B 09
0x8fa1d601d0a2, // INFINEON B 0A
0x89347350bd36, // INFINEON B 0B
0x66d2b7dc39ef, // INFINEON B 0C
0x6bc1e1ae547d, // INFINEON B 0D
0x22729a9bd40f // INFINEON B 0E
};
// Can remember something like that in case of Bigbuf
keyBlock = BigBuf_malloc(STKEYS * 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));
}
// TODO : remember why we actually had need to initialize this array in such specific case
// 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 sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
// validKey[t][sectorNo] = false;
for (uint16_t i = 0; i < 6; i++) {
foundKey[t][sectorNo][i] = 0xff;
}
}
}
int key = -1;
bool err = 0;
bool trapped = 0;
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_);
currline = 20;
curlline = 20;
currfline = 24;
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 ]");
vtsend_set_attribute(NULL, 0);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
while (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) {
WDT_HIT();
}
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_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "\t\t\t `---> Breaking keys ---->");
cjSetCursRight();
DbprintfEx(FLAG_NOLOG, "\t%sGOT TAG :%s %08x%s", _RED_, _CYAN_, cjcuid, _WHITE_);
if (cjcuid == 0) {
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s>>%s BUG: 0000_CJCUID! Retrying...", _RED_, _WHITE_);
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();
//---------------------------------------------------------------------------
// WE SHOULD FIND A WAY TO GET UID TO AVOID THIS "TESTRUN"
// --------------------------------------------------------
// + HERE IS TO BE THOUGHT AS ONLY A KEY SHOULD BE CHECK
// `-+ THEN WE FILL EMULATOR WITH KEY
// `-+ WHEN WE FILL EMULATOR CARD WITH A KEY
// `-+ IF THERE IS ANY FAIL DURING ANY POINT, WE START BACK CHECKING B KEYS
// `-+ THEN FILL EMULATOR WITH B KEEY
// `-+ THEN EMULATOR WITH CARD WITH B KEY
// `-+ IF IT HAS FAILED OF ANY OF SORT THEN WE ARE MARRON LIKE POMALO.
//----------------------------------------------------------------------------
// AN EVEN BETTER IMPLEMENTATION IS TO CHECK EVERY KEY FOR SECTOR 0 KEY A
// THEN IF FOUND CHECK THE SAME KEY FOR NEXT SECTOR ONLY KEY A
// THEN IF FAIL CHECK EVERY SECTOR A KEY FOR EVERY OTHER KEY BUT NOT THE BLOCK
// 0 KEY
// THEN TRY TO READ B KEYS FROM KNOWN A KEYS
// IF FAIL, CHECK SECTOR 0 B KEY WITH SECTOR 0 A KEY
// THEN IF FOUND CHECK EVERY SECTOR FOR SAME B KEY
// ELSE IF FAIL CHECK EVERY KEY FOR SECTOR 0 KEY B
// THEN IF FOUND CHECK SAME KEY FOR ONLY NEXT SECTOR KEY B (PROBABLE A KEY IS
// SAME FOR EVERY SECTOR AND B KEY IS SAME FOR EVERY SECTOR WITH JUST A vs B
// DERIVATION
// THEN IF B KEY IS NOT OF THIS SCHEME CHECK EVERY REMAINING B KEYED SECTOR
// WITH EVERY REMAINING KEYS, BUT DISCARDING ANY DEFAULT TRANSPORT KEYS.
//-----------------------------------------------------------------------------
// also we could avoid first UID check for every block
// then lets expose this “optimal case” of “well known vigik schemes” :
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);
break;
} else if (key == -2) {
err = 1; // Can't select card.
allKeysFound = false;
// cmd_send(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];
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);*/
switch (key64) {
/////////////////////////////////////////////////////////
// COMMON SCHEME 1 : INFINITRON/HEXACT
case 0x484558414354:
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, " .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%sDetected: %s INFI_HEXACT_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_);
;
// Type 0 / A first
uint16_t t = 0;
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
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_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();
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_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_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_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_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_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);
}
}
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();
DbprintfEx(FLAG_NOLOG, "%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, " .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s Detected :%sNORALSY_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_);
;
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_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();
DbprintfEx(FLAG_NOLOG, "SEC: %02x ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
}
trapped = 1;
break;
////////////////END OF SCHEME 3//////////////////////////////
}
/* etc etc for testing schemes quick schemes */
}
}
}
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_);
cjSetCursLeft();
return;
}
/* Settings keys to emulator */
emlClearMem();
uint8_t mblock[16];
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
for (uint8_t t = 0; t < 2; t++) {
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
}
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
}
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s>>%s Setting Keys->Emulator MEM...[%sOK%s]", _YELLOW_, _WHITE_, _GREEN_, _WHITE_);
/* filling TAG to emulator */
uint8_t filled = 0;
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s>>%s Filling Emulator <- from A keys...", _YELLOW_, _WHITE_);
e_MifareECardLoad(sectorsCnt, 0, 0, &filled);
if (filled != 1) {
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%s>>%s W_FAILURE ! %sTrying fallback B keys....", _RED_, _ORANGE_, _WHITE_);
/* no trace, no dbg */
e_MifareECardLoad(sectorsCnt, 1, 0, &filled);
if (filled != 1) {
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "FATAL:EML_FALLBACKFILL_B");
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
return;
}
}
end_time = GetTickCount();
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();
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(0, 0, 0, NULL);
vtsend_cursor_position_restore(NULL);
DbprintfEx(FLAG_NOLOG, "[ SIMUL ENDED ]%s", _GREEN_, _WHITE_);
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "<- 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 !");
saMifareMakeTag();
cjSetCursLeft();
vtsend_cursor_position_restore(NULL);
DbprintfEx(FLAG_NOLOG, "%s[ CLONED? ]", _CYAN_);
DbprintfEx(FLAG_NOLOG, "-> 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_);
cjSetCursLeft();
vtsend_set_attribute(NULL, 0);
return;
}
/* Abusive microgain on original MifareECardLoad :
* - *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;
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];
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)) {
isOK = false;
if (MF_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);
break;
}
} else {
if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "Sector[%2d]. Auth nested error", sectorNo);
break;
}
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if (isOK && mifare_classic_readblock(pcs, cjcuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "Error reading sector %2d block %2d", sectorNo, 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);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
}
} else {
*datain = 0;
}
}
}
if (mifare_classic_halt(pcs, cjcuid)) {
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "Halt error");
};
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if (MF_DBGLEVEL >= 2)
DbpString("EMUL FILL SECTORS FINISHED\n");
}
/* . . . */
/* the chk function is a piwied(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;
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)) {
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "%sFATAL%s : E_MF_LOSTTAG", _RED_, _WHITE_);
return -1;
}
uint64_t ui64Key = bytes_to_num(datain + i * 6, 6);
if (mifare_classic_auth(pcs, cjcuid, 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;
}
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);
return -1;
}
void saMifareMakeTag(void) {
// uint8_t cfail = 0;`
cjSetCursLeft();
cjTabulize();
vtsend_cursor_position_save(NULL);
vtsend_set_attribute(NULL, 1);
DbprintfEx(FLAG_NOLOG, "[ CLONING ]");
vtsend_set_attribute(NULL, 0);
cjSetCursFRight();
DbprintfEx(FLAG_NOLOG, ">> Write to Special:");
int flags = 0;
LED_A_ON(); // yellow
for (int blockNum = 0; blockNum < 16 * 4; blockNum++) {
uint8_t mblock[16];
// 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;
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_RAWPRINT,"FATAL:E_MF_CHINESECOOK_NORICE");
// cfail=1;
// return;
continue;
} else {
cjSetCursLeft();
cjSetCursLeft();
DbprintfEx(FLAG_NOLOG, "`--> %sFAIL%s : CHN_FAIL_BLK_%02x_NOK", _RED_, _WHITE_, blockNum);
cjSetCursFRight();
DbprintfEx(FLAG_NOLOG, "%s>>>>%s STOP AT %02x", _RED_, _WHITE_, blockNum);
break;
}
cjSetCursFRight();
DbprintfEx(FLAG_NOLOG, "%s>>>>>>>> END <<<<<<<<%s", _YELLOW_, _WHITE_);
// break;
/*if (cfail == 1) {
DbprintfEx(FLAG_RAWPRINT,"FATAL: E_MF_HARA_KIRI_\r\n");
break;
} */
}
}
//-----------------------------------------------------------------------------
// Matt's StandAlone mod.
// 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
// 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
byte_t isOK = 0;
// uint8_t uid[10] = {0x00};
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();
// 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");
break;
};
if (mifare_classic_halt(NULL, cjcuid)) {
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "Halt error");
break;
};
};
// reset chip
if (needWipe) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "wipeC error");
break;
};
if (mifare_classic_halt(NULL, cjcuid)) {
if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "Halt error");
break;
};
};
// chaud
// write block
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "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");
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)) {
// if (MF_DBGLEVEL >= 1)
DbprintfEx(FLAG_NOLOG, "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");
break;
};
}
isOK = 1;
break;
}
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
return isOK;
}

View file

@ -0,0 +1,501 @@
//-----------------------------------------------------------------------------
// Colin Brigato 2016, 2017
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef FALSE
#define FALSE 0
#endif
#ifndef __HF_COLIN_H
#define __HF_COLIN_H
#include "proxmark3.h"
#include "mifareutil.h"
#include "iso14443a.h"
//#include "printf.h"
#include "protocols.h"
#include "util.h"
#include "standalone.h" // standalone definitions
#include <stdbool.h> // for bool
#include <stdio.h>
#include <string.h>
//#include <stdio.h>
#include "vtsend.h"
#include "apps.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_
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);
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);
const char clearTerm[8] = {0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, '\0'};
#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,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x0d, 0x0a, 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, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d,
0x31, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x0d, 0x0a, 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, 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, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35,
0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 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, 0x38,
0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x20,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31,
0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x20, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x33, 0x38, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34,
0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d,
0x31, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x34, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d,
0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 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, 0x31, 0x34, 0x35,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x20,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x31, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x33, 0x37, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x30, 0x32, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x0d, 0x0a, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38,
0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38,
0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x30, 0x32, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x0d,
0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33,
0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 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, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35,
0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30,
0x32, 0x6d, 0x30, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38,
0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x35, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35,
0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x35, 0x39, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20,
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x30, 0x20, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34,
0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d,
0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x30, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x0d, 0x0a, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x30, 0x31, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32,
0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x31, 0x37, 0x6d, 0x30, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31,
0x30, 0x32, 0x6d, 0x31, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34,
0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30, 0x0d, 0x0a, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35,
0x32, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33,
0x6d, 0x30, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32,
0x33, 0x30, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30,
0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x34, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x38, 0x30, 0x6d, 0x30, 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, 0x32, 0x32, 0x33, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b,
0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x32, 0x33, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x34, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 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, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39,
0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x32, 0x33, 0x31, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31,
0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x30, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x38, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x31, 0x34, 0x35, 0x6d, 0x30, 0x0d, 0x0a, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38,
0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x35, 0x32, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d, 0x31, 0x1b, 0x5b,
0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b,
0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b,
0x31, 0x33, 0x38, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x38, 0x6d,
0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x31, 0x30, 0x31, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x32, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35, 0x6d, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d,
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 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, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d,
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[] = {
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,
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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0d,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x31, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 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, 0x20, 0x20, 0x20, 0x20, 0x20,
0x0d, 0x0a, 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, 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, 0x30, 0x30, 0x31, 0x31, 0x20, 0x31, 0x31, 0x31, 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, 0x20, 0x20, 0x20,
0x20, 0x0d, 0x0a, 0x30, 0x30, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30,
0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31,
0x30, 0x31, 0x30, 0x31, 0x20, 0x30, 0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x31, 0x31, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x31, 0x30,
0x30, 0x31, 0x30, 0x30, 0x31, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x31, 0x30, 0x31,
0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x20, 0x20,
0x30, 0x31, 0x30, 0x31, 0x31, 0x20, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x30, 0x31, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x31,
0x31, 0x31, 0x30, 0x20, 0x20, 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, 0x0d, 0x0a, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x30, 0x30,
0x30, 0x31, 0x30, 0x31, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x20,
0x20, 0x31, 0x31, 0x30, 0x30, 0x31, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x31, 0x31, 0x30,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x20, 0x30,
0x31, 0x31, 0x20, 0x20, 0x31, 0x30, 0x30, 0x31, 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, 0x0d, 0x0a, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x31, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31,
0x30, 0x31, 0x30, 0x31, 0x30, 0x20, 0x31, 0x31, 0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x31, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x30, 0x31, 0x31, 0x30, 0x20, 0x30, 0x31, 0x31, 0x30, 0x20, 0x30, 0x31,
0x31, 0x20, 0x20, 0x31, 0x31, 0x31, 0x20, 0x31, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x31, 0x30, 0x30, 0x31, 0x30, 0x30, 0x20, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31,
0x30, 0x30, 0x20, 0x30, 0x30, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x31,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0x31, 0x30, 0x20, 0x30, 0x31, 0x31,
0x20, 0x20, 0x30, 0x30, 0x31, 0x20, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x30, 0x31, 0x31, 0x30, 0x30, 0x30, 0x20, 0x31, 0x31, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31,
0x30, 0x30, 0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x31, 0x20, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x30, 0x31, 0x30, 0x31, 0x20, 0x30, 0x31, 0x31, 0x20, 0x20, 0x30, 0x30, 0x31, 0x20,
0x20, 0x30, 0x31, 0x30, 0x20, 0x30, 0x31, 0x30, 0x31, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x30, 0x30, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20,
0x20, 0x20, 0x30, 0x30, 0x31, 0x31, 0x30, 0x31, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x31, 0x31,
0x30, 0x31, 0x31, 0x31, 0x20, 0x31, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30,
0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x20, 0x20, 0x20, 0x30, 0x31, 0x20, 0x30, 0x31, 0x31, 0x20, 0x20,
0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x30, 0x31, 0x31, 0x30,
0x20, 0x20, 0x20, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31,
0x30, 0x31, 0x31, 0x30, 0x30, 0x20, 0x30, 0x31, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x30,
0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x30, 0x31, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x20, 0x31, 0x30,
0x30, 0x30, 0x20, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 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, 0x0d, 0x0a, 0x31, 0x31, 0x30, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x31, 0x30, 0x31,
0x30, 0x30, 0x31, 0x20, 0x30, 0x31, 0x31, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31,
0x31, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20, 0x31, 0x31, 0x31, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31,
0x30, 0x20, 0x20, 0x20, 0x31, 0x30, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31,
0x31, 0x20, 0x20, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 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, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x31, 0x31, 0x31, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30,
0x30, 0x30, 0x31, 0x30, 0x20, 0x30, 0x31, 0x30, 0x30, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31,
0x30, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30, 0x30,
0x30, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x30, 0x31, 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, 0x30, 0x30, 0x31, 0x31, 0x31, 0x30, 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, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0d, 0x0a, 0x20, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x30, 0x31, 0x31, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31,
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;
#endif /* __HF_COLIN_H */

View file

@ -0,0 +1,286 @@
//-----------------------------------------------------------------------------
// Matías A. Ré Medina 2016
// Christian Herrmann, 2018
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for HF aka MattyRun by Matías A. Ré Medina
//-----------------------------------------------------------------------------
/*
### What I did:
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.
### What it does now:
It will check if the keys from the attacked tag are a subset from
the hardcoded set of keys inside of the FPGA. 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 and make a clone
on a blank card.
#### TODO:
- Nested attack in the case not all keys are known.
- Dump into magic card in case of needed replication.
#### ~ Basically automates commands without user intervention.
#### ~ No need of interface.
#### ~ Just a portable battery or an OTG usb cable for power supply.
## Spanish full description of the project [here](http://bit.ly/2c9nZXR).
*/
#include "hf_mattyrun.h"
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().
*/
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// usb_disable(); // Comment this line if you want to see debug messages.
/*
Pseudo-configuration block.
*/
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.
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;
/*
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);
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("--------------------------------------------------------");
}
/*
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.
*/
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], 6);
}
block < 127 ? (block += 4) : (block += 16);
}
}
/*
TODO: This.
If at least one key was found, start a nested attack based on that key, and continue.
*/
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
}
/*
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
Mifare1ksim(0, 0, 0, NULL);
LED_B_OFF();
/*
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;
// 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 != 1) {
Dbprintf("\t✕ Memory could not be filled due to errors.");
LED_C_ON();
}
}
}
}

View file

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Matías A. Ré Medina 2016
// Christian Herrmann, 2018
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __HF_MATTYRUN_H
#define __HF_MATTYRUN_H
//#include <stdbool.h> // for bool
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#define OPTS 2
#endif /* __HF_MATTYRUN_H */

View file

@ -0,0 +1,261 @@
//-----------------------------------------------------------------------------
// Craig Young, 2014
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for HF standalone mode Mifare /sniff/emulation by Craig Young
//-----------------------------------------------------------------------------
#include "hf_young.h"
typedef struct {
uint8_t uid[10];
uint8_t uidlen;
uint8_t atqa[2];
uint8_t sak;
} __attribute__((__packed__)) card_clone_t;
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
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);
for (;;) {
WDT_HIT();
// exit from Standalone Mode, send a usbcommand.
if (usb_poll_validate_length()) return;
SpinDelay(300);
if (iGotoRecord == 1 || cardRead[selected] == 0) {
iGotoRecord = 0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// 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);
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);
LEDsoff();
LED(selected + 1, 0);
// Next state is replay:
playing = 1;
cardRead[selected] = 1;
}
/* MF Classic UID clone */
else if (iGotoClone==1) {
iGotoClone=0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 250);
// 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);
// wait for button to be released
// Delay cloning until card is in place
while (BUTTON_PRESS())
WDT_HIT();
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);
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.
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}, 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);
// 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_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
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
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);
}
}
}

View file

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Craig Young 2014
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __HF_YOUNG_H
#define __HF_YOUNG_H
#include <stdbool.h> // for bool
#include "standalone.h" // standalone definitions
#include "iso14443a.h"
#include "protocols.h"
#define OPTS 2
#endif /* __HF_YOUNG_H */

View file

@ -0,0 +1,328 @@
//-----------------------------------------------------------------------------
// Samy Kamkar, 2012
// Federico Dotta, 2015
// Maurizio Agazzini, 2015
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//
// PROXMARK3 - HID CORPORATE 1000 BRUTEFORCER (STAND-ALONE MODE)
//
// This version of Proxmark3 firmware adds one extra stand-alone mode to proxmark3 firmware.
// 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),
// 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
//
//-----------------------------------------------------------------------------------
// main code for LF aka HID corporate brutefore by Federico Dotta & Maurizio Agazzini
//-----------------------------------------------------------------------------------
#include "lf_hidbrute.h"
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
//SpinDelay(300);
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// record
DbpString("[+] starting recording");
// wait for button to be released
while(BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[+] recorded %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_ORANGE, 0);
// record
Dbprintf("[+] cloning %x %x %08x", selected, high[selected], low[selected]);
// wait for button to be released
while(BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[+] cloned %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
// 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;
LEDsoff();
LED(selected + 1, 0);
// Begin transmitting
if (playing && selected != 2) {
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) {
DbpString("[+] exiting");
LEDsoff();
return;
}
/* 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 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_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;
Dbprintf("[+] Proxbrute - starting decrementing card number");
while (cardnum >= 0) {
// Needed for exiting from proxbrute when button is pressed
if (BUTTON_PRESS()) {
if (BUTTON_HELD(1000) > 0) {
DbpString("[+] exiting");
LEDsoff();
return;
} 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);
}
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) {
DbpString("[+] exiting");
LEDsoff();
return;
} 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) {
DbpString("Exiting");
LEDsoff();
return;
}
/* 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();
}
}
}
}
// 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) {
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
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;
// 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;
// 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
// simulate a HID tag until the button is pressed or after #numcycles cycles
// Used to bruteforce HID in standalone mode.

View file

@ -0,0 +1,24 @@
//-----------------------------------------------------------------------------
// Samy Kamkar 2012
// Federico Dotta, 2015
// Maurizio Agazzini, 2015
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __LF_HIDBRUTE_H
#define __LF_HIDBRUTE_H
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#define OPTS 3
void hid_corporate_1000_calculate_checksum_and_set( uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc);
#endif /* __LF_HIDBRUTE_H */

View file

@ -0,0 +1,168 @@
//-----------------------------------------------------------------------------
// Samy Kamkar, 2011, 2012
// Brad antoniewicz 2011
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for LF aka Proxbrute by Brad antoniewicz
//-----------------------------------------------------------------------------
#include "lf_proxbrute.h"
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
//SpinDelay(300);
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// record
DbpString("[+] starting recording");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[+] recorded %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_ORANGE, 0);
// record
Dbprintf("[+] cloning %x %x %08x", selected, high[selected], low[selected]);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[+] cloned %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
// 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;
LEDsoff();
LED(selected + 1, 0);
// Begin transmitting
if (playing) {
LED(LED_GREEN, 0);
DbpString("[+] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* START PROXBRUTE */
/*
ProxBrute - brad a. - foundstone
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;
}
Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i);
CmdHIDsimTAGEx(high[selected], i, 0, 20000);
SpinDelay(500);
}
} 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");
}
/* END PROXBRUTE */
if (BUTTON_HELD(1000) > 0) {
DbpString("[+] exiting");
LEDsoff();
return;
}
/* 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();
}
}
}
}

View file

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
// Samy Kamkar, 2011, 2012
// Brad antoniewicz 2011
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __LF_PROXBRUTE_H
#define __LF_PROXBRUTE_H
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#define OPTS 2
#endif /* __LF_PROXBRUTE_H */

View file

@ -0,0 +1,134 @@
//-----------------------------------------------------------------------------
// Samy Kamkar, 2012
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for LF aka SamyRun by Samy Kamkar
//-----------------------------------------------------------------------------
#include "lf_samyrun.h"
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
//SpinDelay(300);
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// record
DbpString("[+] starting recording");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[+] recorded %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_ORANGE, 0);
// record
Dbprintf("[+] cloning %x %x %08x", selected, high[selected], low[selected]);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[+] cloned %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
// 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;
LEDsoff();
LED(selected + 1, 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) {
DbpString("[+] exiting");
LEDsoff();
return;
}
/* 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();
}
}
}
}

View file

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Samy Kamkar 2012
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __LF_SAMYRUN_H
#define __LF_SAMYRUN_H
//#include <stdbool.h> // for bool
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#define OPTS 2
#endif /* __LF_SAMYRUN_H */

View file

@ -0,0 +1,28 @@
# 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`.
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.
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
Samples:
### -DWITH_LF_ICERUN
### -DWITH_LF_SAMYRUN
### -DWITH_LF_PROXBRUTE
### -DWITH_LF_HIDBRUTE
### -DWITH_HF_YOUNG
### -DWITH_HF_MATTYRUN
## 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.

View file

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod header file
//-----------------------------------------------------------------------------
#ifndef __STANDALONE_H
#define __STANDALONE_H
#include <stdbool.h> // for bool
#include <inttypes.h> // PRIu64
extern void RunMod();
#endif /* __STANDALONE_H */

1170
armsrc/aes.c Normal file

File diff suppressed because it is too large Load diff

34
armsrc/aes.h Normal file
View file

@ -0,0 +1,34 @@
/*
* AES Cryptographic Algorithm Header File. Include this header file in
* your source which uses these given APIs. (This source is kept under
* public domain)
*/
#ifndef __AES_H
#define __AES_H
// AES context structure
typedef struct {
unsigned int Ek[60];
unsigned int Dk[60];
unsigned int Iv[4];
unsigned char Nr;
unsigned char Mode;
} AesCtx;
// key length in bytes
#define KEY128 16
#define KEY192 24
#define KEY256 32
// block size in bytes
#define BLOCKSZ 16
// mode
#define EBC 0
#define CBC 1
// AES API function prototype
int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode);
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

File diff suppressed because it is too large Load diff

View file

@ -8,34 +8,31 @@
//-----------------------------------------------------------------------------
// Definitions internal to the app source.
//-----------------------------------------------------------------------------
#ifndef __APPS_H
#define __APPS_H
#include <stdint.h>
#include <stddef.h>
#include "common.h"
#include "hitag2.h"
#include "mifare.h"
#ifdef __cplusplus
extern "C" {
#endif
// The large multi-purpose buffer, typically used to hold A/D samples,
// maybe processed in some way.
uint32_t BigBuf[10000];
// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT
#define TRACE_OFFSET 0
#define TRACE_SIZE 3000
#define RECV_CMD_OFFSET 3032
#define RECV_CMD_SIZE 64
#define RECV_RES_OFFSET 3096
#define RECV_RES_SIZE 64
#define DMA_BUFFER_OFFSET 3160
#define DMA_BUFFER_SIZE 4096
#define FREE_BUFFER_OFFSET 7256
#define FREE_BUFFER_SIZE 2744
#include <stdlib.h>
#include <stdarg.h>
#include "common.h"
#include "usb_cdc.h"
#include "crc32.h"
#include "lfdemod.h"
#include "BigBuf.h"
#include "fpgaloader.h"
#include "hitag2.h"
#include "hitagS.h"
#include "mifare.h"
#include "pcf7931.h"
#include "desfire.h"
#include "iso14443b.h"
#include "Standalone/standalone.h"
#include "flashmem.h"
extern const uint8_t OddByteParity[256];
extern uint8_t *trace; // = (uint8_t *) BigBuf;
extern int traceLen; // = 0;
extern int rsamples; // = 0;
extern int tracing; // = TRUE;
extern uint8_t trigger;
@ -47,170 +44,207 @@ extern uint8_t trigger;
/// appmain.h
void ReadMem(int addr);
void __attribute__((noreturn)) AppMain(void);
void SamyRun(void);
//void DbpIntegers(int a, int b, int c);
void DbpString(char *str);
void Dbprintf(const char *fmt, ...);
void DbprintfEx(uint32_t cmd, const char *fmt, ...);
void Dbhexdump(int len, uint8_t *d, bool bAsci);
int AvgAdc(int ch);
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
#define MAX_ADC_HF_VOLTAGE 36300
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
#define MAX_ADC_HF_VOLTAGE_RDV40 140800
// ADC Vref = 3300mV, and an (10000k+240k):240k voltage divider on the LF input can measure voltages up to 140800 mV
#define MAX_ADC_LF_VOLTAGE 140800
uint16_t AvgAdc(int ch);
void print_result(char *name, uint8_t *buf, size_t len);
void PrintToSendBuffer(void);
void ToSendStuffBit(int b);
void ToSendReset(void);
void ListenReaderField(int limit);
void AcquireRawAdcSamples125k(int at134khz);
void SnoopLFRawAdcSamples(int divisor, int trigger_threshold);
void DoAcquisition125k(int trigger_threshold);
extern int ToSendMax;
extern uint8_t ToSend[];
extern uint32_t BigBuf[];
/// fpga.h
void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(int bitstream_version);
int FpgaGatherBitstreamVersion();
void FpgaGatherVersion(char *dst, int len);
void FpgaSetupSsc(void);
void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len);
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
void SetAdcMuxFor(uint32_t whichGpio);
// Definitions for the FPGA commands.
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
#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)
// 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)
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<5)
// Options for LF_ADC
#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)
// Options for the HF reader, tx to tag
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
// Options for the HF reader, correlating against rx from tag
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2)
// Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)
#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)
#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0)
#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0)
// Options for ISO14443A
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
extern void StandAloneMode(void);
extern void printStandAloneModes(void);
/// lfops.h
extern uint8_t decimation;
extern uint8_t bits_per_sample ;
extern bool averaging;
void AcquireRawAdcSamples125k(int divisor);
void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,uint8_t *command);
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command);
void ReadTItag(void);
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
void AcquireTiType(void);
void AcquireRawBitsTI(void);
void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycles);
void SimulateTagLowFrequency(int period, int gap, int ledcontrol);
void CmdHIDsimTAG(int hi, int lo, int ledcontrol);
void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol);
void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol);
void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an ioProx card to T5557/T5567
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 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);
void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol);
void CopyIOtoT55x7(uint32_t hi, uint32_t lo); // Clone an ioProx card to T5557/T5567
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567
void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5);
void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo);
void CopyIndala64toT55x7(int hi, int lo); // Clone Indala 64-bit tag by UID to T55x7
void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7); // Clone Indala 224-bit tag by UID to T55x7
void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode);
void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode );
void T55xxReadTrace(void);
int DemodPCF7931(uint8_t **outBlocks);
int IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block);
void ReadPCF7931();
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
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 T55xxWakeUp(uint32_t Pwd);
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 Cotag(uint32_t arg0);
/// iso14443.h
void SimulateIso14443Tag(void);
void AcquireRawAdcSamplesIso14443(uint32_t parameter);
void ReadSTMemoryIso14443(uint32_t);
void RAMFUNC SnoopIso14443(void);
/// iso14443b.h
void SimulateIso14443bTag(uint32_t pupi);
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 ClearFpgaShiftingRegisters(void);
// iso14443a.h
void RAMFUNC SniffIso14443a(uint8_t param);
void SimulateIso14443aTag(int tagType, int flags, uint8_t *data);
void ReaderIso14443a(UsbCommand *c);
/// iso14443a.h
void RAMFUNC SnoopIso14443a(uint8_t param);
void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data);
void ReaderIso14443a(UsbCommand * c);
// Also used in iclass.c
bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool readerToTag);
uint32_t GetParity(const uint8_t * pbtCmd, int iLen);
//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 iso14a_set_trigger(bool enable);
void iso14a_clear_trace();
void iso14a_set_tracing(bool enable);
void RAMFUNC SniffMifare(uint8_t param);
// 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);
/// epa.h
// epa.h
void EPA_PACE_Collect_Nonce(UsbCommand * c);
void EPA_PACE_Replay(UsbCommand *c);
// mifarecmd.h
void ReaderMifare(bool first_try);
int32_t dist_nt(uint32_t nt1, uint32_t nt2);
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareUReadBlock(uint8_t arg0,uint8_t *datain);
void MifareUReadCard(uint8_t arg0,uint8_t *datain);
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
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 MifareUWriteBlock(uint8_t arg0,uint8_t *datain);
void MifareUWriteBlock_Special(uint8_t arg0,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 MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_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 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(uint32_t arg0, uint32_t arg1, uint32_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 MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
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 MifareUSetPwd(uint8_t arg0, uint8_t *datain);
void OnSuccessMagic();
void OnErrorMagic(uint8_t reason);
/// iso15693.h
int32_t dist_nt(uint32_t nt1, uint32_t nt2);
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);
// mifaredesfire.h
bool InitDesfireCard();
void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain);
void MifareDesfireGetInformation();
void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain);
void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain);
int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout);
size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout);
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);
// iso15693.h
void RecordRawAdcSamplesIso15693(void);
void AcquireRawAdcSamplesIso15693(void);
void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg
void SimTagIso15693(uint32_t parameter); // simulate an ISO15693 tag - greg
void 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 SetDebugIso15693(uint32_t flag);
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 SnoopIClass(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);
//int doIClassSimulation(uint8_t csn[], int breakAfterMacReceived);
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_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);
// cmd.h
bool cmd_receive(UsbCommand* cmd);
bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len);
bool cmd_send(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void* data, size_t len);
/// util.h
// util.h
void HfSnoop(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();
#ifdef __cplusplus
}
#endif
#endif

86
armsrc/buzzer.c Normal file
View file

@ -0,0 +1,86 @@
#include "buzzer.h"
void Ring_BEE_ONCE(uint16_t music_note) {
BEE_ON();
SpinDelayUs(music_note);
BEE_OFF();
SpinDelayUs(music_note);
}
void ring_2_7khz(uint16_t 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_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);
}
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_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_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();
*/
}

50
armsrc/buzzer.h Normal file
View file

@ -0,0 +1,50 @@
/*******
--by sww.2017.4.6
*******/
#ifndef __BUZZER_H
#define __BUZZER_H
#include <stdarg.h>
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#define n_2_7khz 185
#define note_1 956
#define note_2 851
#define note_3 758
#define note_4 715
#define note_5 638
#define note_6 568
#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);
#endif

View file

@ -1,95 +0,0 @@
/* crypto1.c
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, US
Copyright (C) 2008-2008 bla <blapost@gmail.com>
*/
#include "crapto1.h"
#include <stdlib.h>
#define SWAPENDIAN(x)\
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
void crypto1_create(struct Crypto1State *s, uint64_t key)
{
// struct Crypto1State *s = malloc(sizeof(*s));
int i;
for(i = 47;s && i > 0; i -= 2) {
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
s->even = s->even << 1 | BIT(key, i ^ 7);
}
return;
}
void crypto1_destroy(struct Crypto1State *state)
{
// free(state);
state->odd = 0;
state->even = 0;
}
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
{
int i;
for(*lfsr = 0, i = 23; i >= 0; --i) {
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
}
}
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
{
uint32_t feedin;
uint8_t ret = filter(s->odd);
feedin = ret & !!is_encrypted;
feedin ^= !!in;
feedin ^= LF_POLY_ODD & s->odd;
feedin ^= LF_POLY_EVEN & s->even;
s->even = s->even << 1 | parity(feedin);
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
return ret;
}
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted)
{
uint8_t i, ret = 0;
for (i = 0; i < 8; ++i)
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
return ret;
}
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
{
uint32_t i, ret = 0;
for (i = 0; i < 32; ++i)
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
return ret;
}
/* prng_successor
* helper used to obscure the keystream during authentication
*/
uint32_t prng_successor(uint32_t x, uint32_t n)
{
SWAPENDIAN(x);
while(n--)
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x);
}

446
armsrc/des.c Normal file
View file

@ -0,0 +1,446 @@
/* des.c */
/*
This file is part of the ARM-Crypto-Lib.
Copyright (C) 2006-2010 Daniel Otte (daniel.otte@rub.de)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file des.c
* \author Daniel Otte
* \email daniel.otte@rub.de
* \date 2007-06-16
* \brief DES and EDE-DES implementation
* \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
};
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 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 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 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
};
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
};
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
};
/*
1 0
1 0
2 1
2 1
2 1
2 1
2 1
2 1
----
1 0
2 1
2 1
2 1
2 1
2 1
2 1
1 0
*/
#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<ob; ++byte){
uint8_t x,t=0;
for(bit=0; bit<8; ++bit){
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;
}
/******************************************************************************/
static inline
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);
}
/******************************************************************************/
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;
}
/******************************************************************************/
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;
}
/******************************************************************************/
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);
return ret;
}
/******************************************************************************/
typedef struct {
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){
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);
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){
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);
}
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_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]){
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;
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;
}
}
/******************************************************************************/

115
armsrc/des.h Normal file
View file

@ -0,0 +1,115 @@
/* des.h */
/*
This file is part of the ARM-Crypto-Lib.
Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \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_
#include <stdint.h>
#include <string.h>
/* the FIPS 46-3 (1999-10-25) name for triple DES is triple data encryption algorithm so TDEA.
* Also we only implement the three key mode */
/** \def tdea_enc
* \brief defining an alias for void tdes_enc(void* out, const void* in, const void* key)
*/
/** \def tdea_dec
* \brief defining an alias for void tdes_dec(void* out, const void* in, const void* key)
*/
#define tdea_enc tdes_enc
#define tdea_dec tdes_dec
/** \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);
/** \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);
/** \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);
/** \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]);
// Copied from des.h in desfire imp.
typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */
typedef unsigned long DES3_KS[48][2]; /* Triple-DES key schedule */
extern int Asmversion; /* 1 if we're linked with an asm version, 0 if C */
#endif /*DES_H_*/

638
armsrc/desfire_crypto.c Normal file
View file

@ -0,0 +1,638 @@
/*-
* 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
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* $Id$
*/
/*
* This implementation was written based on information provided by the
* following documents:
*
* NIST Special Publication 800-38B
* Recommendation for Block Cipher Modes of Operation: The CMAC Mode for Authentication
* May 2005
*/
#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);
// iceman, see memxor inside string.c, dest/src swapped..
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);
const uint8_t R = (kbs == 8) ? 0x1B : 0x87;
uint8_t l[kbs];
memset (l, 0, kbs);
uint8_t ivect[kbs];
memset (ivect, 0, kbs);
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);
xor = l[0] & 0x80;
lsl (key->cmac_sk1, kbs);
if (xor)
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);
xor = key->cmac_sk1[0] & 0x80;
lsl (key->cmac_sk2, kbs);
if (xor)
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));
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);
} else {
xor (key->cmac_sk1, buffer + len - kbs, kbs);
}
mifare_cypher_blocks_chained (NULL, key, ivect, buffer, len, MCD_SEND, MCO_ENCYPHER);
memcpy (cmac, ivect, kbs);
free(buffer);
}
size_t key_block_size (const desfirekey_t key) {
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;
}
return block_size;
}
/*
* Size of MACing produced with the 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;
}
return mac_length;
}
/*
* 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) {
if ((!nbytes) || (nbytes % block_size))
return ((nbytes / block_size) + 1) * block_size;
else
return nbytes;
}
/*
* 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);
}
/*
* 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 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;
}
}
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);
}
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;
bool append_mac = true;
desfirekey_t key = DESFIRE(tag)->session_key;
if (!key)
return data;
switch (communication_settings & MDCM_MASK) {
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.
*/
append_mac = false;
/* pass through */
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;
// 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);
memcpy (mac, res + edl - 8, 4);
// 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++;
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);
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;
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;
// Fill in the crypto buffer with data ...
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;
}
}
// ... and padding
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:
*nbytes = -1;
res = NULL;
break;
}
return res;
}
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;
desfirekey_t key = DESFIRE(tag)->session_key;
if (!key)
return data;
// Return directly if we just have a status code.
if (1 == *nbytes)
return res;
switch (communication_settings & MDCM_MASK) {
case MDCM_PLAIN:
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;
#ifdef WITH_DEBUG
Dbprintf ("No room for MAC!");
#endif
break;
}
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];
}
int n = (communication_settings & CMAC_VERIFY) ? 8 : 0;
cmac (key, DESFIRE (tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE (tag)->cmac);
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;
} else {
*nbytes -= 8;
}
}
break;
}
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) {
#ifdef WITH_DEBUG
/* FIXME In some configurations, the file is transmitted PLAIN */
Dbprintf("CRC not verified in decyphered stream");
#endif
DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1;
res = NULL;
}
break;
default:
Dbprintf("Unknown communication settings");
*nbytes = -1;
res = NULL;
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)
{
uint8_t ovect[MAX_CRYPTO_BLOCK_SIZE];
if (direction == MCD_SEND) {
xor (ivect, data, block_size);
} else {
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);
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 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;
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);
if (direction == MCD_SEND) {
memcpy (ivect, data, block_size);
} else {
xor (ivect, data, block_size);
memcpy (ivect, ovect, block_size);
}
}
/*
* This function performs all CBC cyphering / deciphering.
*
* The tag argument may be NULL, in which case both key and ivect shall be set.
* When using the tag session_key and ivect for processing data, these
* arguments should be set to NULL.
*
* 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) {
size_t block_size;
if (tag) {
if (!key)
key = DESFIRE (tag)->session_key;
if (!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;
}
}
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);
offset += block_size;
}
}

18
armsrc/desfire_crypto.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __DESFIRE_CRYPTO_H
#define __DESFIRE_CRYPTO_H
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include "crc32.h"
#include "printf.h"
#include "desfire.h"
#include "iso14443a.h"
#ifdef __cplusplus
}
#endif
#endif

156
armsrc/desfire_key.c Normal file
View file

@ -0,0 +1,156 @@
/*-
* 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
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include "desfire_key.h"
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));
// }
}
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++)
data[n] &= 0xfe;
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_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++)
data[n] &= 0xfe;
for (int n=8; n < 16; n++)
data[n] |= 0x01;
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_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++)
data[n] &= 0xfe;
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_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) {
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 version = 0;
for (int n = 0; n < 8; n++) {
version |= ((key->data[n] & 1) << (7 - n));
}
return 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));
key->data[n] &= 0xfe;
key->data[n] |= version_bit;
if (key->type == T_DES) {
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;
}
}
}
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;
}
}

20
armsrc/desfire_key.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef __DESFIRE_KEY_INCLUDED
#define __DESFIRE_KEY_INCLUDED
#include <stdlib.h>
#include <stdint.h>
#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

View file

@ -5,17 +5,14 @@
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support the German eletronic "Personalausweis" (ID card)
// Routines to support the German electronic "Personalausweis" (ID card)
// Note that the functions which do not implement USB commands do NOT initialize
// the card (with iso14443a_select_card etc.). If You want to use these
// functions, You need to do the setup before calling them!
//-----------------------------------------------------------------------------
#include "iso14443a.h"
#include "epa.h"
#include "cmd.h"
// Protocol and Parameter Selection Request
// Protocol and Parameter Selection Request for ISO 14443 type A cards
// use regular (1x) speed in both directions
// CRC is already included
static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6};
@ -74,6 +71,54 @@ static const uint8_t oid_pace_start[] = {
0x04 // id-PACE
};
// APDUs for replaying:
// MSE: Set AT (initiate PACE)
static uint8_t apdu_replay_mse_set_at_pace[41];
// General Authenticate (Get Nonce)
static uint8_t apdu_replay_general_authenticate_pace_get_nonce[8];
// General Authenticate (Map Nonce)
static uint8_t apdu_replay_general_authenticate_pace_map_nonce[75];
// General Authenticate (Mutual Authenticate)
static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75];
// General Authenticate (Perform Key Agreement)
static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18];
// pointers to the APDUs (for iterations)
static struct {
uint8_t len;
uint8_t *data;
} const apdus_replay[] = {
{sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace},
{sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce},
{sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce},
{sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate},
{sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement}
};
// lengths of the replay APDUs
static uint8_t apdu_lengths_replay[5];
// type of card (ISO 14443 A or B)
static char iso_type = 0;
//-----------------------------------------------------------------------------
// Wrapper for sending APDUs to type A and B cards
//-----------------------------------------------------------------------------
int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response)
{
switch(iso_type)
{
case 'a':
return iso14_apdu(apdu, (uint16_t) length, response);
break;
case 'b':
return iso14443b_apdu(apdu, length, response);
break;
default:
return 0;
break;
}
}
//-----------------------------------------------------------------------------
// Closes the communication channel and turns off the field
//-----------------------------------------------------------------------------
@ -81,6 +126,7 @@ void EPA_Finish()
{
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
iso_type = 0;
}
//-----------------------------------------------------------------------------
@ -101,16 +147,16 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
pace_version_info_t *pace_info)
{
size_t index = 0;
while (index <= length - 2) {
// determine type of element
// SET or SEQUENCE
if (data[index] == 0x31 || data[index] == 0x30) {
// enter the set (skip tag + length)
index += 2;
// extended length
// check for extended length
if ((data[index - 1] & 0x80) != 0) {
index += (data[index] & 0x7F);
index += (data[index-1] & 0x7F);
}
}
// OID
@ -158,7 +204,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
index += 2 + data[index + 1];
}
}
// TODO: We should check whether we reached the end in error, but for that
// we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO)
return 0;
@ -176,29 +222,31 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
// we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame)
uint8_t response_apdu[262];
int rapdu_length = 0;
// select the file EF.CardAccess
rapdu_length = iso14_apdu((uint8_t *)apdu_select_binary_cardaccess,
rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
sizeof(apdu_select_binary_cardaccess),
response_apdu);
if (rapdu_length != 6
if (rapdu_length < 6
|| response_apdu[rapdu_length - 4] != 0x90
|| response_apdu[rapdu_length - 3] != 0x00)
{
DbpString("Failed to select EF.CardAccess!");
return -1;
}
// read the file
rapdu_length = iso14_apdu((uint8_t *)apdu_read_binary,
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;
@ -213,17 +261,11 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
//-----------------------------------------------------------------------------
static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return)
{
// // step in which the failure occured
// ack->arg[0] = step;
// // last return code
// ack->arg[1] = func_return;
// power down the field
EPA_Finish();
// send the USB packet
cmd_send(CMD_ACK,step,func_return,0,0,0);
//UsbSendPacket((void *)ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,step,func_return,0,0,0);
}
//-----------------------------------------------------------------------------
@ -243,22 +285,15 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
*/
// return value of a function
int func_return;
int func_return = 0;
// // initialize ack with 0s
// memset(ack->arg, 0, 12);
// memset(ack->d.asBytes, 0, 48);
// set up communication
func_return = EPA_Setup();
if (func_return != 0) {
if (func_return != 0) {
EPA_PACE_Collect_Nonce_Abort(1, func_return);
return;
}
// increase the timeout (at least some cards really do need this!)
iso14a_set_timeout(0x0002FFFF);
// read the CardAccess file
// this array will hold the CardAccess file
uint8_t card_access[256] = {0};
@ -279,11 +314,11 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
EPA_PACE_Collect_Nonce_Abort(3, func_return);
return;
}
// initiate the PACE protocol
// use the CAN for the password since that doesn't change
func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
// now get the nonce
uint8_t nonce[256] = {0};
uint8_t requested_size = (uint8_t)c->arg[0];
@ -294,15 +329,12 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
EPA_PACE_Collect_Nonce_Abort(4, func_return);
return;
}
// all done, return
// all done, return
EPA_Finish();
// save received information
// ack->arg[1] = func_return;
// memcpy(ack->d.asBytes, nonce, func_return);
// UsbSendPacket((void *)ack, sizeof(UsbCommand));
cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
}
//-----------------------------------------------------------------------------
@ -323,10 +355,10 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
sizeof(apdu_general_authenticate_pace_get_nonce));
// append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU
apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4;
// send it
uint8_t response_apdu[262];
int send_return = iso14_apdu(apdu,
int send_return = EPA_APDU(apdu,
sizeof(apdu),
response_apdu);
// check if the command succeeded
@ -336,7 +368,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
{
return -1;
}
// if there is no nonce in the RAPDU, return here
if (send_return < 10)
{
@ -351,7 +383,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
}
// copy the nonce
memcpy(nonce, response_apdu + 6, nonce_length);
return nonce_length;
}
@ -397,7 +429,7 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
apdu[4] = apdu_length - 5;
// send it
uint8_t response_apdu[6];
int send_return = iso14_apdu(apdu,
int send_return = EPA_APDU(apdu,
apdu_length,
response_apdu);
// check if the command succeeded
@ -410,34 +442,113 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
return 0;
}
//-----------------------------------------------------------------------------
// Perform the PACE protocol by replaying given APDUs
//-----------------------------------------------------------------------------
void EPA_PACE_Replay(UsbCommand *c)
{
uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0};
// if an APDU has been passed, 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;
}
// 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;
}
// increase the timeout (at least some cards really do need this!)/////////////
// iso14a_set_timeout(0x0003FFFF);
// response APDU
uint8_t response_apdu[300] = {0};
// now replay the data and measure the timings
for (int i = 0; i < sizeof(apdu_lengths_replay); i++) {
StartCountUS();
func_return = EPA_APDU(apdus_replay[i].data,
apdu_lengths_replay[i],
response_apdu);
timings[i] = GetCountUS();
// every step but the last one should succeed
if (i < sizeof(apdu_lengths_replay) - 1
&& (func_return < 6
|| response_apdu[func_return - 4] != 0x90
|| response_apdu[func_return - 3] != 0x00))
{
EPA_Finish();
cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20);
return;
}
}
EPA_Finish();
cmd_send(CMD_ACK,0,0,0,timings,20);
return;
}
//-----------------------------------------------------------------------------
// Set up a communication channel (Card Select, PPS)
// Returns 0 on success or a non-zero error code on failure
//-----------------------------------------------------------------------------
int EPA_Setup()
{
// return code
int return_code = 0;
// card UID
uint8_t uid[8];
// card select information
iso14a_card_select_t card_select_info;
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;
// first, look for type A cards
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card
return_code = iso14443a_select_card(uid, &card_select_info, NULL);
if (return_code != 1) {
return 1;
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;
}
// send the PPS request
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
uint8_t pps_response[3];
return_code = ReaderReceive(pps_response);
if (return_code != 3 || pps_response[0] != 0xD0) {
return return_code == 0 ? 2 : return_code;
// 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;
}
return 0;
}
Dbprintf("No card found.");
return 1;
}

View file

@ -11,6 +11,10 @@
#ifndef __EPA_H
#define __EPA_H
#include "cmd.h"
#include "iso14443a.h"
#include "iso14443b.h"
// this struct is used by EPA_Parse_CardAccess and contains info about the
// PACE protocol supported by the chip
typedef struct {
@ -19,7 +23,7 @@ typedef struct {
uint8_t parameter_id;
} pace_version_info_t;
// note: EPA_PACE_GetNonce is declared in apps.h
// note: EPA_PACE_Collect_Nonce and EPA_PACE_Replay are declared in apps.h
// general functions
void EPA_Finish();
@ -33,4 +37,4 @@ int EPA_Setup();
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password);
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce);
#endif /* __EPA_H */
#endif /* __EPA_H */

803
armsrc/felica.c Normal file
View file

@ -0,0 +1,803 @@
#include "proxmark3.h"
#include "apps.h"
#include "BigBuf.h"
#include "util.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "protocols.h"
#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
#ifndef FELICA_REQUEST_GUARD_TIME
# define FELICA_REQUEST_GUARD_TIME (6800/16 + 1)
#endif
// FRAME DELAY TIME 2672 carrier cycles
#ifndef FELICA_FRAME_DELAY_TIME
# 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)
#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)
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 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);
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;
}
uint32_t felica_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
#endif
//structure to hold outgoing NFC frame
static uint8_t frameSpace[NFC_MAX_FRAME_SIZE+4];
//structure to hold incoming NFC frame, used for ISO/IEC 18092-compatible frames
static struct {
enum {
STATE_UNSYNCD,
STATE_TRYING_SYNC,
STATE_GET_LENGTH,
STATE_GET_DATA,
STATE_GET_CRC,
STATE_FULL
} state;
uint16_t shiftReg; //for synchronization and offset calculation
int posCnt;
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;
//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
#endif
static void NFCFrameReset() {
NFCFrame.state = STATE_UNSYNCD;
NFCFrame.posCnt = 0;
NFCFrame.crc_ok = false;
NFCFrame.byte_offset = 0;
}
static void NFCInit(uint8_t *data) {
NFCFrame.framebytes = data;
NFCFrameReset();
}
//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);
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);
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;
}
//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 ( 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;
}
}
/* Perform FeliCa polling card
* Currently does NOT do any collision handling.
* It expects 0-1 cards in the device's range.
*/
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);
// 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;
}
// poll-0: 0xb2,0x4d,0x06,0x00,0xff,0xff,0x00,0x00,0x09,0x21,
// resp: 0xb2,0x4d,0x12,0x01,0x01,0x2e,0x3d,0x17,0x26,0x47,0x80,0x95,0x00,0xf1,0x00,0x00,0x00,0x01,0x43,0x00,0xb3,0x7f,
// 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-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,
// 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 ) {
if (blocknum > 4 || blocknum <= 0)
Dbprintf("Invalid number of blocks, %d. Up to 4 are allowed.", 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);
frameSpace[c++] = SERVICE_FELICA_LITE_READONLY & 0xFF;
//number of blocks
frameSpace[c++] = blocknum;
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);
} else {
frameSpace[c++] = 0x80;
frameSpace[c++] = blocks[i];
}
}
//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) {
volatile uint16_t b;
uint8_t flags = FPGA_MAJOR_MODE_ISO18092;
if ( power )
flags |= FPGA_HF_ISO18092_FLAG_READER;
if (highspeed)
flags |= FPGA_HF_ISO18092_FLAG_424K;
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;
// preamble
// sending 0x00 0x00 0x00 0x00 0x00 0x00
uint16_t c = 0;
while (c < 6) {
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0x00;
c++;
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b;
}
}
// sending sync code
// sending data
c = 0;
while (c < len) {
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = frame[c++];
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b;
}
}
/**/
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
/**/
// 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
// stop when button is pressed
// 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);
NFCFrameReset();
// 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;
}
// Set up FeliCa communication (similar to iso14443a_setup)
// field is setup for "Sending as Reader"
static void felica_setup(uint8_t fpga_minor_mode) {
if (MF_DBGLEVEL > 3) Dbprintf("FeliCa_setup Enter");
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));
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);
// 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);
// Start the timer
StartCountSspClk();
LED_D_ON();
if (MF_DBGLEVEL > 3) Dbprintf("FeliCa_setup Exit");
}
//-----------------------------------------------------------------------------
// 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) {
if (MF_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();
set_tracing(true);
if ((param & FELICA_CONNECT)) {
felica_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
// 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;
}
}
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_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");
}
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);
//the frame bits are slow enough.
int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory
int numbts = 0;
uint8_t *dest = (uint8_t *)BigBuf_get_addr();
uint8_t *destend = dest + n-2;
uint32_t endframe = GetCountSspClk();
while (dest <= destend) {
WDT_HIT();
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);
*dest = distance >> 8;
dest++;
*dest = (distance & 0xff);
dest++;
}
//crc NOT checked
if (NFCFrame.state == STATE_FULL) {
endframe = GetCountSspClk();
//*dest = NFCFrame.crc_ok; //kind of wasteful
dest++;
for(int i=0; i < NFCFrame.len; i++) {
*dest = NFCFrame.framebytes[i];
dest++;
if (dest >= destend ) break;
}
remFrames--;
if (remFrames <= 0) break;
if (dest >= destend ) break;
numbts += NFCFrame.len;
NFCFrameReset();
}
}
}
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);
}
#define R_POLL0_LEN 0x16
#define R_POLL1_LEN 0x18
#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) {
int i, curlen = 0;
uint8_t *curresp = 0;
uint8_t ndef[8];
num_to_bytes(nfcid, 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");
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]
);
//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];
}
//calculate and set CRC
AddCrc(resp_poll0, resp_poll0[2]);
AddCrc(resp_poll1, resp_poll1[2]);
AddCrc(resp_readblk, resp_readblk[2]);
felica_setup( FPGA_HF_ISO18092_FLAG_NOMOD);
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) {
if (NFCFrame.crc_ok) {
if (NFCFrame.framebytes[2] == 6 && NFCFrame.framebytes[3] == 0) {
//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 (NFCFrame.framebytes[2] > 5 && NFCFrame.framebytes[3] == 0x06) {
//we should rebuild it depending on page size, but...
//Let's see first
curresp = resp_readblk;
curlen = R_READBLK_LEN;
listenmode = false;
}
//clear frame
NFCFrameReset();
} 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);
//switch back
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD);
NFCFrameReset();
listenmode = true;
curlen = 0;
curresp = NULL;
}
}
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);
DbpString("Felica Lite-S sim end");
}
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();
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); ) {
// 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) {
dest[cnt++] = liteblks[blknum];
uint8_t *fb = NFCFrame.framebytes;
dest[cnt++] = fb[12];
dest[cnt++] = fb[13];
//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();
//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
set_tracelen(cnt);
cmd_send(CMD_ACK, isOK, cnt, 0, 0, 0);
}

417
armsrc/flashmem.c Normal file
View file

@ -0,0 +1,417 @@
#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
/*
1-256256
CS拉高
*/
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
// 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);
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// 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);
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// 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
// 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
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
}
void FlashStop(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;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// 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();
}
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
uint16_t incoming = 0;
WDT_HIT();
// 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;
// wait recive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0)
WDT_HIT();
// reading incoming data
incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
return incoming;
}
// send last byte over SPI
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}
// 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;
}
// 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;
}
// determine whether FLASHMEM is busy
bool Flash_CheckBusy(uint16_t times) {
bool ret = (Flash_ReadStat1() & BUSY);
if (!ret || !times || !(times--))
return ret;
while (times) {
WDT_HIT();
SpinDelay(1);
ret = (Flash_ReadStat1() & BUSY);
if (!ret)
break;
times--;
}
return ret;
}
// read ID out
uint8_t Flash_ReadID(void) {
if (Flash_CheckBusy(100)) return 0;
// Manufacture ID / device ID
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
uint8_t man_id = FlashSendByte(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;
return 0;
}
// read unique id for chip.
void Flash_UniqueID(uint8_t *uid) {
if (Flash_CheckBusy(100)) return;
// 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[3] = FlashSendByte(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);
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.
// 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;
}
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return 0;
}
Flash_ReadStat1();
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;
}
// 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;
}
// enable the flash write
void Flash_WriteEnable() {
FlashSendLastByte(WRITEENABLE);
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash Write enabled");
}
// 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;
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
}
/*
// 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;
}
*/
// erase 64k at one time
// since a block is 64kb, and there is four blocks.
// we only need block number, as MSB
// execution time: 1s / 1000ms
// 0x00 00 00 -- 0x 00 FF FF == block 0
// 0x01 00 00 -- 0x 01 FF FF == block 1
// 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;
}
// 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;
}
void Flashmem_print_status(void) {
DbpString("Flash memory");
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();
}

139
armsrc/flashmem.h Normal file
View file

@ -0,0 +1,139 @@
/* Arduino SPIFlash Library v.2.5.0
* Copyright (C) 2015 by Prajwal Bhattaram
* Modified by Prajwal Bhattaram - 13/11/2016
*
* This file is part of the Arduino SPIFlash Library. This library is for
* Winbond NOR flash memory modules. In its current form it enables reading
* and writing individual data variables, structs and arrays from and to various locations;
* reading and writing pages; continuous read functions; sector, block and chip erase;
* suspending and resuming programming/erase and powering down for low power operation.
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License v3.0
* along with the Arduino SPIFlash Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Common Instructions //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#ifndef __FLASHMEM_H
#define __FLASHMEM_H
#include "proxmark3.h"
#include "apps.h"
#include "ticks.h"
// Used Command
#define ID 0x90
#define MANID 0x90
#define JEDECID 0x9F
#define READSTAT1 0x05
#define READSTAT2 0x35
#define WRITESTAT 0x01
#define WRITEDISABLE 0x04
#define WRITEENABLE 0x06
#define READDATA 0x03
#define PAGEPROG 0x02
#define SECTORERASE 0x20
#define BLOCK32ERASE 0x52
#define BLOCK64ERASE 0xD8
#define CHIPERASE 0xC7
#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
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Chip specific instructions //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~ 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
// List of blocks
#define MAX_BLOCKS 4
#define MAX_SECTORS 16
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
extern void Dbprintf(const char *fmt, ...);
void FlashSetup(void);
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_WriteEnable();
bool Flash_WipeMemoryPage(uint8_t page);
bool Flash_WipeMemory();
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_WriteData(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void);
#endif

View file

@ -9,18 +9,44 @@
// Routines to load the FPGA image, and then to configure the FPGA's major
// mode once it is configured.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "fpgaloader.h"
// remember which version of the bitstream we have already downloaded to the FPGA
static int downloaded_bitstream = 0;
// this is where the bitstreams are located in memory:
extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end;
static uint8_t *fpga_image_ptr = NULL;
static uint32_t uncompressed_bytes_cnt;
#define OUTPUT_BUFFER_LEN 80
//-----------------------------------------------------------------------------
// Set up the Serial Peripheral Interface as master
// Used to write the FPGA config word
// May also be used to write to other SPI attached devices like an LCD
//-----------------------------------------------------------------------------
void SetupSpi(int mode)
{
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;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// 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
@ -28,65 +54,62 @@ void SetupSpi(int mode)
// 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_NCS2 |
GPIO_MISO |
GPIO_MOSI |
GPIO_SPCK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
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;
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);
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)
(14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(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
( 8 << 4) | // Bits per Transfer (16 bits)
AT91C_SPI_BITS_16 | // Bits per Transfer (16 bits)
( 0 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
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:
/*
case SPI_LCD_MODE:
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)
(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
( 1 << 4) | // Bits per Transfer (9 bits)
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: // Disable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
*/
default:
DisableSpi();
break;
}
}
@ -95,8 +118,7 @@ void SetupSpi(int mode)
// Set up the synchronous serial port, with the one set of options that we
// always use when we are talking to the FPGA. Both RX and TX are enabled.
//-----------------------------------------------------------------------------
void FpgaSetupSsc(void)
{
void FpgaSetupSscExt(uint8_t clearPCER) {
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
@ -105,11 +127,14 @@ void FpgaSetupSsc(void)
GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
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);
@ -127,31 +152,102 @@ void FpgaSetupSsc(void)
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
}
void FpgaSetupSsc(void) {
FpgaSetupSscExt(true);
}
//-----------------------------------------------------------------------------
// 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
// ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed.
//-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, int len)
{
if (buf == NULL) {
return false;
}
bool FpgaSetupSscDma(uint8_t *buf, int len) {
if (buf == NULL) return false;
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
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
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
return true;
FpgaEnableSscDma();
return true;
}
static void DownloadFPGA_byte(unsigned char w)
{
//----------------------------------------------------------------------------
// Uncompress (inflate) the FPGA data. Returns one decompressed byte with
// each call.
//----------------------------------------------------------------------------
static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
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 < 0)
return res;
}
uncompressed_bytes_cnt++;
return *fpga_image_ptr++;
}
//----------------------------------------------------------------------------
// Undo the interleaving of several FPGA config files. FPGA config files
// are combined into one big file:
// 288 bytes from FPGA file 1, followed by 288 bytes from FGPA file 2, etc.
//----------------------------------------------------------------------------
static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) {
// skip undesired data belonging to other bitstream_versions
get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
static voidpf fpga_inflate_malloc(voidpf opaque, uInt items, uInt size) {
return BigBuf_malloc(items*size);
}
// free eventually allocated BigBuf memory
static void fpga_inflate_free(voidpf opaque, voidpf address) {
BigBuf_free(); BigBuf_Clear_ext(false);
}
//----------------------------------------------------------------------------
// Initialize decompression of the respective (HF or LF) FPGA stream
//----------------------------------------------------------------------------
static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE];
uncompressed_bytes_cnt = 0;
// initialize z_stream structure for inflate:
compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
compressed_fpga_stream->zalloc = &fpga_inflate_malloc;
compressed_fpga_stream->zfree = &fpga_inflate_free;
inflateInit2(compressed_fpga_stream, 0);
fpga_image_ptr = output_buffer;
for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++)
header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
// Check for a valid .bit file (starts with bitparse_fixed_header)
if (memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0)
return true;
return false;
}
static void DownloadFPGA_byte(unsigned char w) {
#define SEND_BIT(x) { if(w & (1<<x) ) HIGH(GPIO_FPGA_DIN); else LOW(GPIO_FPGA_DIN); HIGH(GPIO_FPGA_CCLK); LOW(GPIO_FPGA_CCLK); }
SEND_BIT(7);
SEND_BIT(6);
@ -163,11 +259,9 @@ static void DownloadFPGA_byte(unsigned char w)
SEND_BIT(0);
}
// Download the fpga image starting at FpgaImage and with length FpgaImageLen bytes
// If bytereversal is set: reverse the byte order in each 4-byte word
static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int bytereversal)
{
int i=0;
// Download the fpga image starting at current stream position with length FpgaImageLen bytes
static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
int i = 0;
AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
@ -205,7 +299,7 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
SpinDelay(50);
HIGH(GPIO_FPGA_NPROGRAM);
i=100000;
i = 100000;
// wait for FPGA ready to accept data signal
while ((i) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT ) ) ) {
i--;
@ -218,25 +312,17 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
return;
}
if(bytereversal) {
/* This is only supported for uint32_t aligned images */
if( ((int)FpgaImage % sizeof(uint32_t)) == 0 ) {
i=0;
while(FpgaImageLen-->0)
DownloadFPGA_byte(FpgaImage[(i++)^0x3]);
/* Explanation of the magic in the above line:
* i^0x3 inverts the lower two bits of the integer i, counting backwards
* for each 4 byte increment. The generated sequence of (i++)^3 is
* 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 etc. pp.
*/
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;
}
} else {
while(FpgaImageLen-->0)
DownloadFPGA_byte(*FpgaImage++);
DownloadFPGA_byte(b);
}
// continue to clock FPGA until ready signal goes high
i=100000;
i = 100000;
while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) {
HIGH(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_CCLK);
@ -250,165 +336,91 @@ static void DownloadFPGA(const char *FpgaImage, int FpgaImageLen, int byterevers
LED_D_OFF();
}
static char *bitparse_headers_start;
static char *bitparse_bitstream_end;
static int bitparse_initialized = 0;
/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence
* 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01
* After that the format is 1 byte section type (ASCII character), 2 byte length
* (big endian), <length> bytes content. Except for section 'e' which has 4 bytes
* length.
*/
static const char _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01};
static int bitparse_init(void * start_address, void *end_address)
{
bitparse_initialized = 0;
if(memcmp(_bitparse_fixed_header, start_address, sizeof(_bitparse_fixed_header)) != 0) {
return 0; /* Not matched */
} else {
bitparse_headers_start= ((char*)start_address) + sizeof(_bitparse_fixed_header);
bitparse_bitstream_end= (char*)end_address;
bitparse_initialized = 1;
return 1;
}
}
int bitparse_find_section(char section_name, char **section_start, unsigned int *section_length)
{
char *pos = bitparse_headers_start;
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;
if(!bitparse_initialized) return 0;
while(pos < bitparse_bitstream_end) {
char current_name = *pos++;
unsigned int current_length = 0;
if(current_name < 'a' || current_name > 'e') {
#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) {
switch (current_name) {
case 'e':
/* Four byte length field */
current_length += (*pos++) << 24;
current_length += (*pos++) << 16;
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 += (*pos++) << 8;
current_length += (*pos++) << 0;
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) {
if (current_name != 'e' && current_length > 255) {
/* Maybe a parse error */
break;
}
if(current_name == section_name) {
if (current_name == section_name) {
/* Found it */
*section_start = pos;
*section_length = current_length;
result = 1;
break;
}
pos += current_length; /* Skip section */
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;
}
//-----------------------------------------------------------------------------
// Find out which FPGA image format is stored in flash, then call DownloadFPGA
// with the right parameters to download the image
//-----------------------------------------------------------------------------
extern char _binary_fpga_lf_bit_start, _binary_fpga_lf_bit_end;
extern char _binary_fpga_hf_bit_start, _binary_fpga_hf_bit_end;
void FpgaDownloadAndGo(int bitstream_version)
{
void *bit_start;
void *bit_end;
//----------------------------------------------------------------------------
// Check which FPGA image is currently loaded (if any). If necessary
// decompress and load the correct (HF or LF) image to the FPGA
//----------------------------------------------------------------------------
void FpgaDownloadAndGo(int bitstream_version) {
// check whether or not the bitstream is already loaded
if (FpgaGatherBitstreamVersion() == bitstream_version)
if (downloaded_bitstream == bitstream_version)
return;
z_stream compressed_fpga_stream;
uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00};
bool verbose = (MF_DBGLEVEL > 3);
// make sure that we have enough memory to decompress
BigBuf_free(); BigBuf_Clear_ext(verbose);
if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer))
return;
if (bitstream_version == FPGA_BITSTREAM_LF) {
bit_start = &_binary_fpga_lf_bit_start;
bit_end = &_binary_fpga_lf_bit_end;
} else if (bitstream_version == FPGA_BITSTREAM_HF) {
bit_start = &_binary_fpga_hf_bit_start;
bit_end = &_binary_fpga_hf_bit_end;
} else
return;
/* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start
*/
if(bitparse_init(bit_start, bit_end)) {
/* Successfully initialized the .bit parser. Find the 'e' section and
* send its contents to the FPGA.
*/
char *bitstream_start;
unsigned int bitstream_length;
if(bitparse_find_section('e', &bitstream_start, &bitstream_length)) {
DownloadFPGA(bitstream_start, bitstream_length, 0);
return; /* All done */
}
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;
}
/* Fallback for the old flash image format: Check for the magic marker 0xFFFFFFFF
* 0xAA995566 at address 0x102000. This is raw bitstream with a size of 336,768 bits
* = 10,524 uint32_t, stored as uint32_t e.g. little-endian in memory, but each DWORD
* is still to be transmitted in MSBit first order. Set the invert flag to indicate
* that the DownloadFPGA function should invert every 4 byte sequence when doing
* the bytewise download.
*/
if( *(uint32_t*)0x102000 == 0xFFFFFFFF && *(uint32_t*)0x102004 == 0xAA995566 )
DownloadFPGA((char*)0x102000, 10524*4, 1);
}
inflateEnd(&compressed_fpga_stream);
int FpgaGatherBitstreamVersion()
{
char temp[256];
FpgaGatherVersion(temp, sizeof (temp));
if (!memcmp("LF", temp, 2))
return FPGA_BITSTREAM_LF;
else if (!memcmp("HF", temp, 2))
return FPGA_BITSTREAM_HF;
return FPGA_BITSTREAM_ERR;
}
void FpgaGatherVersion(char *dst, int len)
{
char *fpga_info;
unsigned int fpga_info_len;
dst[0] = 0;
if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) {
strncat(dst, "FPGA image: legacy image without version information", len-1);
} else {
/* USB packets only have 48 bytes data payload, so be terse */
if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
if (!memcmp("fpga_lf", fpga_info, 7))
strncat(dst, "LF ", len-1);
else if (!memcmp("fpga_hf", fpga_info, 7))
strncat(dst, "HF ", len-1);
}
strncat(dst, "FPGA image built", len-1);
#if 0
if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
strncat(dst, " for ", len-1);
strncat(dst, fpga_info, len-1);
}
#endif
if(bitparse_find_section('c', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
strncat(dst, " on ", len-1);
strncat(dst, fpga_info, len-1);
}
if(bitparse_find_section('d', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) {
strncat(dst, " at ", len-1);
strncat(dst, fpga_info, len-1);
}
}
// turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// free eventually allocated BigBuf memory
BigBuf_free(); BigBuf_Clear_ext(false);
}
//-----------------------------------------------------------------------------
@ -416,19 +428,18 @@ void FpgaGatherVersion(char *dst, int len)
// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
// where C is the 4 bit command and D is the 12 bit data
//-----------------------------------------------------------------------------
void FpgaSendCommand(uint16_t cmd, uint16_t v)
{
void FpgaSendCommand(uint16_t cmd, uint16_t v) {
SetupSpi(SPI_FPGA_MODE);
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data
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
// vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to
// avoid changing this function's occurence everywhere in the source code.
//-----------------------------------------------------------------------------
void FpgaWriteConfWord(uint8_t v)
{
void FpgaWriteConfWord(uint8_t v) {
FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);
}
@ -437,8 +448,7 @@ void FpgaWriteConfWord(uint8_t v)
// closable, but should only close one at a time. Not an FPGA thing, but
// the samples from the ADC always flow through the FPGA.
//-----------------------------------------------------------------------------
void SetAdcMuxFor(uint32_t whichGpio)
{
void SetAdcMuxFor(uint32_t whichGpio) {
AT91C_BASE_PIOA->PIO_OER =
GPIO_MUXSEL_HIPKD |
GPIO_MUXSEL_LOPKD |
@ -452,9 +462,33 @@ void SetAdcMuxFor(uint32_t whichGpio)
GPIO_MUXSEL_HIRAW;
LOW(GPIO_MUXSEL_HIPKD);
LOW(GPIO_MUXSEL_LOPKD);
#ifndef WITH_FPC
LOW(GPIO_MUXSEL_HIRAW);
LOW(GPIO_MUXSEL_LORAW);
LOW(GPIO_MUXSEL_LOPKD);
#endif
HIGH(whichGpio);
}
void Fpga_print_status(void) {
Dbprintf("Currently loaded FPGA image");
Dbprintf(" mode....................%s", fpga_version_information[downloaded_bitstream-1]);
}
int FpgaGetCurrent(void) {
return downloaded_bitstream;
}
// 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();
}

98
armsrc/fpgaloader.h Normal file
View file

@ -0,0 +1,98 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, April 2006
// iZsh <izsh at fail0verflow.com>, 2014
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to load the FPGA image, and then to configure the FPGA's major
// mode once it is configured.
//-----------------------------------------------------------------------------
#ifndef __FPGALOADER_H
#define __FPGALOADER_H
#include <stdint.h>
#include <stdbool.h>
#include "apps.h"
#include "fpga.h"
#include "common.h" // standard definitions
#include "proxmark3.h" // common area
#include "string.h"
#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 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);
// definitions for multiple FPGA config files support
#define FPGA_BITSTREAM_LF 1
#define FPGA_BITSTREAM_HF 2
//#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)
// 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)
// 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)
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<5)
// Options for LF_ADC
#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)
// Options for the HF reader, tx to tag
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
// Options for the HF reader, correlating against rx from tag
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
// 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
// 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)
//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

78
armsrc/hfsnoop.c Normal file
View file

@ -0,0 +1,78 @@
#include "proxmark3.h"
#include "apps.h"
#include "BigBuf.h"
#include "util.h"
#include "usb_cdc.h" // for usb_poll_validate_length
static void RAMFUNC optimizedSnoop(void);
static void RAMFUNC optimizedSnoop(void)
{
int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory
uint16_t *dest = (uint16_t *)BigBuf_get_addr();
uint16_t *destend = dest + n-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());
}
void HfSnoop(int samplesToSkip, int triggersToSkip)
{
BigBuf_free(); BigBuf_Clear();
Dbprintf("Skipping first %d sample pairs, Skipping %d triggers.\n", samplesToSkip, triggersToSkip);
int trigger_cnt;
LED_D_ON();
// Select correct configs
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc();
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);
SpinDelay(100);
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); // Setting Frame Mode For better performance on high speed data transfer.
trigger_cnt = 0;
uint16_t r = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
r = (uint16_t)AT91C_BASE_SSC->SSC_RHR;
r = MAX(r & 0xff, r >> 8);
if (r >= 180) {
if (++trigger_cnt > triggersToSkip)
break;
}
}
}
if (!BUTTON_PRESS()) {
int waitcount = samplesToSkip; // lets wait 40000 ticks of pck0
while(waitcount != 0) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY))
waitcount--;
}
optimizedSnoop();
Dbprintf("Trigger kicked! Value: %d, Dumping Samples Hispeed now.", r);
}
//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 Snoop end");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
}

File diff suppressed because it is too large Load diff

2146
armsrc/hitagS.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -12,15 +12,23 @@
#ifndef __ISO14443A_H
#define __ISO14443A_H
#include "common.h"
#include "mifaresniff.h"
// mifare reader over DMA buffer (SnoopIso14443a())!!!
#define MIFARE_BUFF_OFFSET 3560 // \/ \/ \/
// card emulator memory
#define EML_RESPONSES 4000
#define CARD_MEMORY 6000
#define CARD_MEMORY_LEN 4096
#ifdef __cplusplus
extern "C" {
#endif
#include "usb_cmd.h"
#include "cmd.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "crc16.h"
#include "mifaresniff.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "parity.h"
#include "random.h"
#include "mifare.h" // structs
typedef struct {
enum {
@ -35,20 +43,23 @@ typedef struct {
uint16_t bitCount;
uint16_t collisionPos;
uint16_t syncBit;
uint32_t parityBits;
uint8_t parityBits;
uint8_t parityLen;
uint16_t shiftReg;
uint16_t samples;
uint16_t len;
uint32_t startTime, endTime;
uint8_t *output;
uint8_t *parity;
} tDemod;
/*
typedef enum {
MOD_NOMOD = 0,
MOD_SECOND_HALF,
MOD_FIRST_HALF,
MOD_BOTH_HALVES
} Modulation_t;
*/
typedef struct {
enum {
@ -61,37 +72,70 @@ typedef struct {
// DROP_FIRST_HALF,
} state;
uint16_t shiftReg;
uint16_t bitCount;
int16_t bitCount;
uint16_t len;
uint16_t byteCntMax;
//uint16_t byteCntMax;
uint16_t posCnt;
uint16_t syncBit;
uint32_t parityBits;
uint16_t highCnt;
uint16_t twoBits;
uint8_t parityBits;
uint8_t parityLen;
uint32_t fourBits;
uint32_t startTime, endTime;
uint8_t *output;
uint8_t *parity;
} tUart;
#ifndef AddCrc14A
# 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)
#endif
extern byte_t oddparity (const byte_t bt);
extern uint32_t GetParity(const uint8_t *pbtCmd, int iLen);
extern void AppendCrc14443a(uint8_t *data, int len);
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
extern void ReaderTransmit(uint8_t *frame, int len, uint32_t *timing);
extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32_t *timing);
extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing);
extern int ReaderReceive(uint8_t *receivedAnswer);
extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr);
extern 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);
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);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr);
extern 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);
extern void iso14a_set_timeout(uint32_t timeout);
extern void iso14a_clear_tracelen();
extern void iso14a_set_tracing(bool enable);
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);
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);
//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 DetectNACKbug();
#ifdef __cplusplus
}
#endif
#endif /* __ISO14443A_H */

1707
armsrc/iso14443b.c Normal file

File diff suppressed because it is too large Load diff

60
armsrc/iso14443b.h Normal file
View file

@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// Merlok - June 2011
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type B.
//-----------------------------------------------------------------------------
#ifndef __ISO14443B_H
#define __ISO14443B_H
#ifdef __cplusplus
extern "C" {
#endif
#include "proxmark3.h"
#include "common.h" // access to global variable: MF_DBGLEVEL
#include "apps.h"
#include "util.h"
#include "string.h"
#include "crc16.h"
#include "mifare.h"
#include "protocols.h"
#ifndef AddCrc14A
# 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)
#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);
// testfunctions
extern void WaitForFpgaDelayQueueIsEmpty( uint16_t delay );
extern 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_ACKNOWLEDGE 5
#define SIM_WORK 6
#ifdef __cplusplus
}
#endif
#endif /* __ISO14443B_H */

File diff suppressed because it is too large Load diff

View file

@ -11,8 +11,7 @@ INCLUDE ../common/ldscript.common
PHDRS
{
fpgaimage PT_LOAD FLAGS(4);
text PT_LOAD;
text PT_LOAD FLAGS(5);
data PT_LOAD;
bss PT_LOAD;
}
@ -20,16 +19,12 @@ PHDRS
ENTRY(Vector)
SECTIONS
{
.fpgaimage : {
*(fpga_lf_bit.data)
*(fpga_hf_bit.data)
} >fpgaimage :fpgaimage
.start : {
*(.startos)
} >osimage :text
.text : {
KEEP(*(stage1_image))
*(.text)
*(.text.*)
*(.eh_frame)
@ -40,12 +35,13 @@ SECTIONS
.rodata : {
*(.rodata)
*(.rodata.*)
*(fpga_all_bit.data)
KEEP(*(.version_information))
. = ALIGN(8);
} >osimage :text
. = ALIGN(4);
.data : {
KEEP(*(compressed_data))
*(.data)
*(.data.*)
*(.ramfunc)
@ -55,6 +51,7 @@ SECTIONS
__data_src_start__ = LOADADDR(.data);
__data_start__ = ADDR(.data);
__data_end__ = __data_start__ + SIZEOF(.data);
__os_size__ = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata);
.bss : {
__bss_start__ = .;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
@ -11,8 +11,38 @@
#ifndef __LEGICRF_H
#define __LEGICRF_H
#include "proxmark3.h" //
#include "apps.h"
#include "util.h" //
#include "string.h"
#include "legic_prng.h" // legic PRNG impl
#include "crc.h" // legic crc-4
#include "ticks.h" // timers
#include "legic.h" // legic_card_select_t struct
extern void LegicRfSimulate(int phase, int frame, int reqresp);
extern int LegicRfReader(int bytes, int offset);
extern void LegicRfWriter(int bytes, int offset);
extern int 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 LegicRfInfo(void);
uint32_t get_key_stream(int skip, int count);
void frame_send_tag(uint16_t response, uint8_t bits);
void frame_sendAsReader(uint32_t data, uint8_t bits);
int legic_read_byte( uint16_t index, uint8_t cmd_sz);
bool legic_write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz);
int legic_select_card(legic_card_select_t *p_card);
int legic_select_card_iv(legic_card_select_t *p_card, uint8_t iv);
void LegicCommonInit(bool clear_mem);
// emulator mem
void LegicEMemSet(uint32_t arg0, uint32_t arg1, uint8_t *data);
void LegicEMemGet(uint32_t arg0, uint32_t arg1);
void legic_emlset_mem(uint8_t *data, int offset, int numofbytes);
void legic_emlget_mem(uint8_t *data, int offset, int numofbytes);
void ice_legic_setup();
#endif /* __LEGICRF_H */

File diff suppressed because it is too large Load diff

452
armsrc/lfsampling.c Normal file
View file

@ -0,0 +1,452 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Miscellaneous routines for low frequency sampling.
//-----------------------------------------------------------------------------
#include "lfsampling.h"
/*
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
*/
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);
}
/**
* Called from the USB-handler to set the sampling configuration
* The sampling config is used for std reading and snooping.
*
* Other functions may read samples and ignore the sampling config,
* such as functions to read the UID from a prox tag or similar.
*
* Values set to '0' implies no change (except for averaging)
* @brief setSamplingConfig
* @param sc
*/
void setSamplingConfig(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;
printConfig();
}
sample_config* getSamplingConfig() {
return &config;
}
struct BitstreamOut {
uint8_t * buffer;
uint32_t numbits;
uint32_t position;
};
/**
* @brief Pushes bit onto the stream
* @param stream
* @param bit
*/
void pushBit( BitstreamOut* stream, uint8_t bit) {
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
/**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna.
* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz
* 0 or 95 ==> 125 KHz
*
**/
void LFSetupFPGAForADC(int divisor, bool lf_field) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ( (divisor == 1) || (divisor < 0) || (divisor > 255) )
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
else if (divisor == 0)
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0));
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 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();
}
/**
* Does the sample acquisition. If threshold is specified, the actual sampling
* is not commenced until the threshold has been reached.
* This method implements decimation and quantization in order to
* be able to provide longer sample traces.
* Uses the following global settings:
* @param decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc.
* @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample.
* @param averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample
* value that will be used is the average value of the three samples.
* @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set
* to -1 to ignore threshold.
* @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples.
*/
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, uint32_t cancel_after) {
//bigbuf, to hold the aquired raw data signal
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 (decimation < 1) decimation = 1;
// Use a bit stream to handle the output
BitstreamOut data = { dest , 0, 0};
int sample_counter = 0;
uint8_t sample = 0;
//If we want to do averaging
uint32_t sample_sum =0 ;
uint32_t sample_total_numbers = 0;
uint32_t sample_total_saved = 0;
uint32_t cancel_counter = 0;
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 (averaging)
sample_sum += sample;
//Check decimation
if (decimation > 1) {
sample_counter++;
if (sample_counter < decimation) continue;
sample_counter = 0;
}
//Averaging
if (averaging && decimation > 1) {
sample = sample_sum / decimation;
sample_sum =0;
}
//Store the sample
sample_total_saved ++;
if (bits_per_sample == 8){
dest[sample_total_saved-1] = sample;
data.numbits = sample_total_saved << 3;//Get the return value correct
if (sample_total_saved >= bufsize) break;
} else {
pushBit(&data, sample & 0x80);
if (bits_per_sample > 1) pushBit(&data, sample & 0x40);
if (bits_per_sample > 2) pushBit(&data, sample & 0x20);
if (bits_per_sample > 3) pushBit(&data, sample & 0x10);
if (bits_per_sample > 4) pushBit(&data, sample & 0x08);
if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
//Not needed, 8bps is covered above
//if (bits_per_sample > 7) pushBit(&data, sample & 0x01);
if ((data.numbits >> 3) +1 >= bufsize) break;
}
}
}
if (!silent) {
Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample", sample_total_saved, sample_total_numbers, bits_per_sample);
Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
}
return data.numbits;
}
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
* This method is typically used by tag-specific readers who just wants to read the samples
* the normal way
* @param trigger_threshold
* @param silent
* @return number of bits sampled
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent) {
return DoAcquisition(1, 8, 0,trigger_threshold, silent, 0, 0);
}
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);
}
uint32_t ReadLF(bool activeField, bool silent, int sample_size) {
if (!silent)
printConfig();
LFSetupFPGAForADC(config.divisor, activeField);
return DoAcquisition_config(silent, sample_size);
}
/**
* Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SampleLF(bool printCfg, int sample_size) {
BigBuf_Clear_ext(false);
uint32_t ret = ReadLF(true, printCfg, sample_size);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret;
}
/**
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SnoopLF() {
BigBuf_Clear_ext(false);
uint32_t ret = ReadLF(false, true, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret;
}
/**
* acquisition of T55x7 LF signal. Similar to other LF, but adjusted with @marshmellows thresholds
* the data is collected in BigBuf.
**/
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;
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;
}
// 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
* and is Manchester?, we directly gather the manchester data into bigbuff
**/
#define COTAG_T1 384
#define COTAG_T2 (COTAG_T1>>1)
#define COTAG_ONE_THRESHOLD 128+30
#define COTAG_ZERO_THRESHOLD 128-30
#ifndef COTAG_BITS
#define COTAG_BITS 264
#endif
void doCotagAcquisition(size_t sample_size) {
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > sample_size )
bufsize = sample_size;
dest[0] = 0;
uint8_t sample = 0, firsthigh = 0, firstlow = 0;
uint16_t i = 0;
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;
}
++i;
if ( sample > COTAG_ONE_THRESHOLD)
dest[i] = 255;
else if ( sample < COTAG_ZERO_THRESHOLD)
dest[i] = 0;
else
dest[i] = dest[i-1];
}
}
}
uint32_t doCotagAcquisitionManchester() {
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > COTAG_BITS )
bufsize = COTAG_BITS;
dest[0] = 0;
uint8_t sample = 0, firsthigh = 0, firstlow = 0;
uint16_t sample_counter = 0, period = 0;
uint8_t curr = 0, prev = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// find first peak
if ( !firsthigh ) {
if (sample < COTAG_ONE_THRESHOLD)
continue;
firsthigh = 1;
}
if ( !firstlow ){
if (sample > COTAG_ZERO_THRESHOLD )
continue;
firstlow = 1;
}
// 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;
}

86
armsrc/lfsampling.h Normal file
View file

@ -0,0 +1,86 @@
#ifndef __LFSAMPLING_H
#define __LFSAMPLING_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "ticks.h" // for StartTicks
typedef struct BitstreamOut BitstreamOut;
/**
* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384
* and is Manchester?, we directly gather the manchester data into bigbuff
**/
void doCotagAcquisition(size_t sample_size);
uint32_t doCotagAcquisitionManchester(void);
/**
* acquisition of T55x7 LF signal. Similar to other LF, but adjusted with @marshmellows thresholds
* the data is collected in BigBuf.
**/
void doT55x7Acquisition(size_t sample_size);
/**
* Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SampleLF(bool silent, int sample_size);
/**
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SnoopLF();
// adds sample size to default options
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after);
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
* This method is typically used by tag-specific readers who just wants to read the samples
* the normal way
* @param trigger_threshold
* @param silent
* @return number of bits sampled
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent);
/**
* @brief Does sample acquisition, using the config values set in the sample_config.
* @param trigger_threshold
* @param silent
* @return number of bits sampled
*/
uint32_t DoAcquisition_config(bool silent, int sample_size);
/**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna.
* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz
* 0 or 95 ==> 125 KHz
*
**/
void LFSetupFPGAForADC(int divisor, bool lf_field);
/**
* Called from the USB-handler to set the sampling configuration
* The sampling config is used for std reading and snooping.
*
* Other functions may read samples and ignore the sampling config,
* such as functions to read the UID from a prox tag or similar.
*
* Values set to '0' implies no change (except for averaging)
* @brief setSamplingConfig
* @param sc
*/
void setSamplingConfig(sample_config *sc);
sample_config * getSamplingConfig();
void printConfig();
#endif // __LFSAMPLING_H

File diff suppressed because it is too large Load diff

View file

@ -17,12 +17,12 @@
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "crc.h"
#include "protocols.h"
#include "parity.h"
#endif

571
armsrc/mifaredesfire.c Normal file
View file

@ -0,0 +1,571 @@
#include "mifaredesfire.h"
#define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 16
#define MAX_DESFIRE_FRAME_SIZE 60
#define NOT_YET_AUTHENTICATED 255
#define FRAME_PAYLOAD_SIZE (MAX_DESFIRE_FRAME_SIZE - 5)
#define RECEIVE_SIZE 64
// 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 __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 };
/* PCB CID CMD PAYLOAD */
//static uint8_t __res[MAX_FRAME_SIZE];
bool InitDesfireCard(){
iso14a_card_select_t card;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(true);
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;
}
// ARG0 flag enums
enum {
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x08,
} CmdOptions ;
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){
/* ARG0 contains flags.
0x01 = init card.
0x02 = Disconnect
0x03
*/
uint8_t flags = arg0;
size_t datalen = arg1;
uint8_t resp[RECEIVE_SIZE];
memset(resp,0,sizeof(resp));
if (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);
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);
}
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);
// 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);
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);
cmd_send(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){
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 IV[16] = {0x00};
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};
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:{
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);
} else {
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);
}
}
}
struct desfire_key defaultkey = {0};
desfirekey_t key = &defaultkey;
if (algo == 2)
Desfire_3des_key_new_with_version(keybytes, key);
else if (algo ==1)
Desfire_des_key_new(keybytes, key);
cmd[0] = AUTHENTICATE;
cmd[1] = keyno; //keynumber
len = DesfireAPDU(cmd, 2, resp);
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if ( resp[2] == 0xaf ){
} else {
DbpString("Authentication failed. Invalid key number.");
OnError(3);
return;
}
memcpy( encRndB, resp+3, 8);
if (algo == 2)
tdes_dec(&decRndB, &encRndB, key->data);
else if (algo == 1)
des_dec(&decRndB, &encRndB, key->data);
memcpy(RndB, 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)
tdes_dec(&encRndA, &decRndA, key->data);
else if (algo == 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)
tdes_dec(&encRndB, &decRndB, key->data);
else if (algo == 1)
des_dec(&encRndB, &decRndB, key->data);
memcpy(both + 8, encRndB, 8);
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd+1, both, 16 );
len = DesfireAPDU(cmd, 17, resp);
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if ( resp[2] == 0x00 ){
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new( RndA, RndB , key, skey );
//print_result("SESSION : ", skey->data, 8);
memcpy(encRndA, resp+3, 8);
if (algo == 2)
tdes_dec(&encRndA, &encRndA, key->data);
else if (algo == 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.");
OnError(4);
return;
}
}
//Change the selected key to a new value.
/*
// Current key is a 3DES key, change it to a DES key
if (algo == 2) {
cmd[0] = CHANGE_KEY;
cmd[1] = keyno;
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) {
cmd[0] = CHANGE_KEY;
cmd[1] = keyno;
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;
while(!len) {
len = DesfireAPDU(cmd,26,resp);
}
}
}
*/
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);
} else {
DbpString("Authentication failed.");
OnError(6);
return;
}
}
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.");
}
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);
}
// 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat 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){
size_t len = 0;
size_t wrappedLen = 0;
uint8_t wCmd[USB_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);
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
}
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);
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;
}
// 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 OnError(uint8_t reason){
cmd_send(CMD_ACK,0,reason,0,0,0);
OnSuccess();
}

14
armsrc/mifaredesfire.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef __MIFAREDESFIRE_H
#define __MIFAREDESFIRE_H
#include "common.h"
#include "proxmark3.h"
#include "apps.h"
#include "string.h"
#include "BigBuf.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "desfire_key.h"
#include "mifareutil.h"
#include "des.h"
#endif

View file

@ -9,165 +9,316 @@
//-----------------------------------------------------------------------------
#include "mifaresniff.h"
#include "apps.h"
static int sniffState = SNF_INIT;
static uint8_t sniffUIDType;
static uint8_t sniffUID[8];
static uint8_t sniffATQA[2];
static uint8_t sniffSAK;
static uint8_t sniffBuf[16];
//static 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
bool MfSniffInit(void){
memset(sniffUID, 0x00, 8);
memset(sniffATQA, 0x00, 2);
sniffSAK = 0;
sniffUIDType = SNF_UID_4;
// 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);
return FALSE;
// 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();
}
bool MfSniffEnd(void){
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();
return FALSE;
}
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader) {
/*
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) {
if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader
// reset on 7-Bit commands from reader
if (reader && (len == 1) && (bitCnt == 7)) {
sniffState = SNF_INIT;
}
switch (sniffState) {
case SNF_INIT:{
if ((len == 1) && (reader) && (bitCnt == 7) ) { // REQA or WUPA from reader
sniffUIDType = SNF_UID_4;
memset(sniffUID, 0x00, 8);
memset(sniffATQA, 0x00, 2);
sniffSAK = 0;
sniffState = SNF_WUPREQ;
// 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_WUPREQ:{
if ((!reader) && (len == 2)) { // ATQA from tag
memcpy(sniffATQA, data, 2);
sniffState = SNF_ATQA;
case SNF_MAGIC_WUPC2: {
if ((len == 1) && (reader) && (data[0] == MIFARE_MAGICWUPC2) ) {
sniffState = SNF_CARD_IDLE;
}
break;
}
case SNF_ATQA:{
if ((reader) && (len == 2) && (data[0] == 0x93) && (data[1] == 0x20)) { // Select ALL from reader
sniffState = SNF_ANTICOL1;
// ATQA from tag
if ((!reader) && (len == 2)) {
sniffATQA[0] = data[0];
sniffATQA[1] = data[1];
sniffState = SNF_UID;
}
break;
}
case SNF_ANTICOL1:{
if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // UID from tag (CL1)
memcpy(sniffUID + 3, data, 4);
sniffState = SNF_UID1;
}
break;
}
case SNF_UID1:{
if ((reader) && (len == 9) && (data[0] == 0x93) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 4 Byte UID from reader
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:{
if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card?
// SAK from card?
if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) {
sniffSAK = data[0];
if (sniffUID[3] == 0x88) { // CL2 UID part to be expected
sniffState = SNF_ANTICOL2;
} else { // select completed
// 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_ANTICOL2:{
if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // CL2 UID
memcpy(sniffUID, sniffUID+4, 3);
memcpy(sniffUID+3, data, 4);
sniffUIDType = SNF_UID_7;
sniffState = SNF_UID2;
}
break;
}
case SNF_UID2:{
if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 2nd part of 7 Byte UID
sniffState = SNF_SAK;
}
break;
}
}
case SNF_CARD_IDLE:{ // trace the card select sequence
sniffBuf[0] = 0xFF;
sniffBuf[1] = 0xFF;
memcpy(sniffBuf + 2, sniffUID, 7);
memcpy(sniffBuf + 9, sniffATQA, 2);
sniffBuf[11] = sniffSAK;
sniffBuf[12] = 0xFF;
sniffBuf[13] = 0xFF;
LogTrace(sniffBuf, 14, 0, parity, true);
} // intentionally no break;
case SNF_CARD_CMD:{
LogTrace(data, len, 0, parity, true);
sniffState = SNF_CARD_RESP;
timerData = GetTickCount();
break;
}
case SNF_CARD_RESP:{
LogTrace(data, len, 0, parity, false);
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;
return false;
}
*/
bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) {
if (traceLen && (GetTickCount() > timerData + maxTimeoutMs)) {
return intMfSniffSend();
}
return FALSE;
}
// internal sending function. not a RAMFUNC.
bool intMfSniffSend() {
int pckSize = 0;
int pckLen = traceLen;
int pckNum = 0;
FpgaDisableSscDma();
while (pckLen > 0) {
pckSize = MIN(USB_CMD_DATA_SIZE, pckLen);
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();
cmd_send(CMD_ACK, 1, pckSize, pckNum, trace + traceLen - pckLen, pckSize);
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();
pckLen -= pckSize;
pckNum++;
}
LED_B_ON();
cmd_send(CMD_ACK,2,0,0,0,0);
cmd_send(CMD_ACK, 2, 0, 0, 0, 0); // 2 == data transfer finished.
LED_B_OFF();
iso14a_clear_trace();
return TRUE;
}
}

View file

@ -15,33 +15,28 @@
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#define SNF_INIT 0
#define SNF_INIT 0
#define SNF_NO_FIELD 1
#define SNF_WUPREQ 2
#define SNF_ATQA 3
#define SNF_ANTICOL1 4
#define SNF_UID1 5
#define SNF_ANTICOL2 6
#define SNF_UID2 7
#define SNF_SAK 8
#define SNF_CARD_IDLE 9
#define SNF_CARD_CMD 10
#define SNF_CARD_RESP 11
#define SNF_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_4 0
#define SNF_UID_7 0
#define SNF_UID_10 0
bool MfSniffInit(void);
bool RAMFUNC MfSniffLogic(const uint8_t * data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader);
bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs);
bool intMfSniffSend();
bool MfSniffEnd(void);
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

View file

@ -8,182 +8,130 @@
//-----------------------------------------------------------------------------
// Work with mifare cards.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1.h"
#include "mifareutil.h"
int MF_DBGLEVEL = MF_DBG_ALL;
// memory management
uint8_t* mifare_get_bigbufptr(void) {
return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET); // was 3560 - tied to other size changes
}
uint8_t* eml_get_bigbufptr_sendbuf(void) {
return (((uint8_t *)BigBuf) + RECV_CMD_OFFSET);
}
uint8_t* eml_get_bigbufptr_recbuf(void) {
return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET);
}
uint8_t* eml_get_bigbufptr_cardmem(void) {
return (((uint8_t *)BigBuf) + CARD_MEMORY);
}
int MF_DBGLEVEL = MF_DBG_ERROR;
// crypto1 helpers
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){
uint8_t bt = 0;
int i;
if (len != 1) {
for (i = 0; i < len; i++)
data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i];
data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i];
} else {
bt = 0;
for (i = 0; i < 4; i++)
bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data[0], i)) << i;
data[0] = bt;
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_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par) {
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;
uint32_t mltpl = 1 << (len - 1); // for len=18 it=0x20000
*par = 0;
par[0] = 0;
for (i = 0; i < len; i++) {
bt = data[i];
data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i];
*par = (*par >> 1) | ( ((filter(pcs->odd) ^ oddparity(bt)) & 0x01) * mltpl );
if ( ( i & 0x0007 ) == 0)
par[ i >> 3 ] = 0;
par[ i >> 3 ] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007)));
}
return;
}
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
uint8_t bt = 0;
int i;
for (i = 0; i < 4; i++)
bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, i)) << i;
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 commands
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing)
{
return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, NULL, timing);
}
int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing)
{
uint8_t dcmd[8];//, ecmd[4];
//uint32_t par=0;
dcmd[0] = cmd;
dcmd[1] = data[0];
dcmd[2] = data[1];
dcmd[3] = data[2];
dcmd[4] = data[3];
dcmd[5] = data[4];
AppendCrc14443a(dcmd, 6);
//Dbprintf("Data command: %02x", dcmd[0]);
//Dbprintf("Data R: %02x %02x %02x %02x %02x %02x %02x", dcmd[1],dcmd[2],dcmd[3],dcmd[4],dcmd[5],dcmd[6],dcmd[7]);
//memcpy(ecmd, dcmd, sizeof(dcmd));
ReaderTransmit(dcmd, sizeof(dcmd), NULL);
int len = ReaderReceive(answer);
if(!len)
{
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout.");
return 2;
}
return len;
}
int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing)
{
uint8_t dcmd[4], ecmd[4];
uint32_t pos, par, res;
// send 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;
}
dcmd[0] = cmd;
dcmd[1] = data;
AppendCrc14443a(dcmd, 2);
// 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;
for (pos = 0; pos < 4; pos++)
{
par[0] = 0;
for (pos = 0; pos < 4; pos++) {
ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos];
par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) * 0x08 );
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 = ReaderReceivePar(answer, &par);
int len = ReaderReceive(answer, par);
if (answer_parity) *answer_parity = par[0];
if (parptr) *parptr = par;
if (crypted == CRYPT_ALL) {
if (len == 1) {
res = 0;
for (pos = 0; pos < 4; pos++)
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], pos)) << pos;
answer[0] = res;
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 commands
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested)
{
// 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, uint64_t isNested, uint32_t * ntptr, uint32_t *timing)
{
// variables
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;
uint8_t tmp4[4];
byte_t par = 0;
byte_t ar[4];
uint32_t nt, ntpp; // Supplied tag nonce
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 = mifare_get_bigbufptr();
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// Transmit MIFARE_CLASSIC_AUTH
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, timing);
if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len);
if (len != 4) return 1;
// "random" reader nonce:
num_to_bytes( prng_successor( GetTickCount(), 32), 4, nr);
ar[0] = 0x55;
ar[1] = 0x41;
ar[2] = 0x49;
ar[3] = 0x92;
// 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);
@ -204,268 +152,361 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
}
// some statistic
if (!ntptr && (MF_DBGLEVEL >= 3))
Dbprintf("auth uid: %08x nt: %08x", uid, nt);
if (!ntptr && (MF_DBGLEVEL >= MF_DBG_EXTENDED))
Dbprintf("auth uid: %08x | nr: %08x | nt: %08x", uid, nr, nt);
// save Nt
if (ntptr)
*ntptr = nt;
par = 0;
// Generate (encrypted) nr+parity by loading it into the cipher (Nr)
for (pos = 0; pos < 4; pos++)
{
mf_nr_ar[pos] = crypto1_byte(pcs, ar[pos], 0) ^ ar[pos];
par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(ar[pos])) & 0x01) * 0x80 );
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);
nt = prng_successor(nt, 32);
// ar+parity
for (pos = 4; pos < 8; pos++)
{
for (pos = 4; pos < 8; pos++) {
nt = prng_successor(nt,8);
mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff);
par = (par >> 1)| ( ((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) * 0x80 );
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 bit answer
len = ReaderReceive(receivedAnswer);
if (!len)
{
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout.");
// Receive 4 byte tag answer
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
if (!len) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout.");
return 2;
}
memcpy(tmp4, receivedAnswer, 4);
ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0);
if (ntpp != bytes_to_num(tmp4, 4)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response.");
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)
{
// variables
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
int len;
uint8_t bt[2];
uint8_t bt[2] = {0x00, 0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, NULL);
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
if (len != 18) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len);
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: wrong response len: %x (expected 18)", len);
return 2;
}
memcpy(bt, receivedAnswer + 16, 2);
AppendCrc14443a(receivedAnswer, 16);
AddCrc14A(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error.");
if (MF_DBGLEVEL >= MF_DBG_ALL) Dbprintf("Cmd CRC response error.");
return 3;
}
memcpy(blockData, receivedAnswer, 16);
return 0;
}
int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData)
{
// variables
int len;
uint8_t bt[2];
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer,NULL);
if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
if (len != 18) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len);
return 2;
}
memcpy(bt, receivedAnswer + 16, 2);
AppendCrc14443a(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error.");
return 3;
}
memcpy(blockData, receivedAnswer, 14);
return 0;
}
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData)
{
// variables
int len, i;
uint32_t pos;
uint32_t par = 0;
byte_t res;
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 = mifare_get_bigbufptr();
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, 0xA0, blockNo, receivedAnswer, NULL);
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
memcpy(d_block, blockData, 16);
AppendCrc14443a(d_block, 16);
AddCrc14A(d_block, 16);
// crypto
par = 0;
for (pos = 0; pos < 18; pos++)
{
for (pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) * 0x20000 );
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);
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
res = 0;
for (i = 0; i < 4; i++)
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], i)) << i;
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 >= 1) Dbprintf("Cmd send data2 Error: %02x", res);
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2;
}
return 0;
}
int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData)
{
// variables
int len;
uint32_t par = 0;
uint8_t d_block[18];
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_WRITEBLOCK
len = mifare_sendcmd_short(NULL, 1, 0xA0, blockNo, receivedAnswer,NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]);
return 1;
}
memset(d_block,'\0',18);
memcpy(d_block, blockData, 16);
AppendCrc14443a(d_block, 16);
ReaderTransmitPar(d_block, sizeof(d_block), par, NULL);
// Receive the response
len = ReaderReceive(receivedAnswer);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len);
return 2;
}
return 0;
}
int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData)
{
// variables
int len;
//uint32_t par = 0;
uint8_t d_block[8];
uint8_t* receivedAnswer = mifare_get_bigbufptr();
// command MIFARE_CLASSIC_WRITEBLOCK
memset(d_block,'\0',8);
d_block[0]= blockNo;
memcpy(d_block+1,blockData,4);
AppendCrc14443a(d_block, 6);
//i know the data send here is correct
len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer,NULL);
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len);
return 1;
}
return 0;
}
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid)
{
// variables
int len;
// Mifare HALT
uint8_t* receivedAnswer = mifare_get_bigbufptr();
return 0;
}
len = mifare_sendcmd_short(pcs, pcs == NULL ? 0:1, 0x50, 0x00, receivedAnswer, NULL);
/* // 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 >= 1) Dbprintf("halt error. response len: %x", len);
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;
}
return 0;
}
int mifare_ultra_halt(uint32_t uid)
{
// variables
int len;
// Mifare HALT
uint8_t* receivedAnswer = mifare_get_bigbufptr();
len = mifare_sendcmd_short(NULL, 1, 0x50, 0x00, receivedAnswer, NULL);
if (len != 0) {
if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len);
return 1;
}
return 0;
}
// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards),
// plus evtl. 8 sectors with 16 blocks each (4k cards)
uint8_t NumBlocksPerSector(uint8_t sectorNo)
{
if (sectorNo < 32)
return 4;
else
return 16;
uint8_t NumBlocksPerSector(uint8_t sectorNo) {
return (sectorNo < 32) ? 4 : 16;
}
uint8_t FirstBlockOfSector(uint8_t sectorNo)
{
uint8_t FirstBlockOfSector(uint8_t sectorNo) {
if (sectorNo < 32)
return sectorNo * 4;
else
@ -473,28 +514,28 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo)
}
// work with emulator memory
void emlSetMem(uint8_t *data, int blockNum, int blocksCount) {
emlSetMem_xt(data, blockNum, blocksCount, 16);
}
// work with emulator memory
void emlSetMem(uint8_t *data, int blockNum, int blocksCount) {
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
memcpy(emCARD + blockNum * 16, data, blocksCount * 16);
void 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 = eml_get_bigbufptr_cardmem();
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 = eml_get_bigbufptr_cardmem();
uint8_t* emCARD = BigBuf_get_EM_addr();
memcpy(data, emCARD + bytePtr, byteCount);
}
int emlCheckValBl(int blockNum) {
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
uint8_t* emCARD = BigBuf_get_EM_addr();
uint8_t* data = emCARD + blockNum * 16;
if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) ||
@ -509,21 +550,19 @@ int emlCheckValBl(int blockNum) {
}
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) {
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
uint8_t* emCARD = BigBuf_get_EM_addr();
uint8_t* data = emCARD + blockNum * 16;
if (emlCheckValBl(blockNum)) {
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 = eml_get_bigbufptr_cardmem();
uint8_t* emCARD = BigBuf_get_EM_addr();
uint8_t* data = emCARD + blockNum * 16;
memcpy(data + 0, &blReg, 4);
@ -540,28 +579,111 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) {
}
uint64_t emlGetKey(int sectorNum, int keyType) {
uint8_t key[6];
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
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) {
int b;
const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04};
uint8_t* emCARD = eml_get_bigbufptr_cardmem();
memset(emCARD, 0, CARD_MEMORY_LEN);
uint8_t* emCARD = BigBuf_get_EM_addr();
memset(emCARD, 0, CARD_MEMORY_SIZE);
// fill sectors trailer data
for(b = 3; b < 256; b<127?(b+=4):(b+=16)) {
emlSetMem((uint8_t *)trailer, b , 1);
}
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;
}

View file

@ -12,74 +12,83 @@
#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_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
// reader voltage field detector
#define MF_MINFIELDV 4000
// debug
// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode
#define MF_DBG_NONE 0
#define MF_DBG_ERROR 1
#define MF_DBG_ALL 2
#define MF_DBG_EXTENDED 4
extern int MF_DBGLEVEL;
//mifare emulator states
#define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1
#define MFEMUL_SELECT1 2
#define MFEMUL_SELECT2 3
#define MFEMUL_AUTH1 4
#define MFEMUL_AUTH2 5
#define MFEMUL_WORK 6
#define MFEMUL_WRITEBL2 7
#define MFEMUL_INTREG_INC 8
#define MFEMUL_INTREG_DEC 9
#define MFEMUL_INTREG_REST 10
#define MFEMUL_HALTED 11
#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
uint8_t* mifare_get_bigbufptr(void);
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing);
int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing);
int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing);
int mifare_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);
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \
uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \
uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_ultra_halt(uint32_t uid);
// 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);
//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_halt();
// desfire
int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing);
int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData);
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
// crypto functions
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par);
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);
// memory management
uint8_t* mifare_get_bigbufptr(void);
uint8_t* eml_get_bigbufptr_sendbuf(void);
uint8_t* eml_get_bigbufptr_recbuf(void);
// Mifare memory structure
uint8_t NumBlocksPerSector(uint8_t sectorNo);
uint8_t FirstBlockOfSector(uint8_t sectorNo);
@ -87,6 +96,7 @@ 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);

View file

267
armsrc/optimized_cipher.c Normal file
View file

@ -0,0 +1,267 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
****************************************************************************/
/**
This file contains an optimized version of the MAC-calculation algorithm. Some measurements on
a std laptop showed it runs in about 1/3 of the time:
Std: 0.428962
Opt: 0.151609
Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can
be easily dropped into a code base.
The optimizations have been performed in the following steps:
* Parameters passed by reference instead of by value.
* Iteration instead of recursion, un-nesting recursive loops into for-loops.
* Handling of bytes instead of individual bits, for less shuffling and masking
* Less creation of "objects", structs, and instead reuse of alloc:ed memory
* Inlining some functions via #define:s
As a consequence, this implementation is less generic. Also, I haven't bothered documenting this.
For a thorough documentation, check out the MAC-calculation within cipher.c instead.
-- MHS 2015
**/
#include "optimized_cipher.h"
#define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14)^ (s->t >> 10)^ (s->t >> 8)^ (s->t >> 5)^ (s->t >> 4)^ (s->t >> 1)^ s->t))
#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))
/*
* 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;
//r: r0 r1 r2 r3 r4 r5 r6 r7
//r_ls2: r2 r3 r4 r5 r6 r7 0 0
// z0
// z1
// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1);
// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x;
return (z0 & 4) | (z1 & 2) | (z2 & 1);
}
*/
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->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;
}
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);
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] >> 4);
opt_successor(k, &x2, head, s);
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] >> 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);
}
}
}
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_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);
}
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;
}
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;
}
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;
}
/**
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
* two functions, since the first 8 bytes are known, we can pre-calculate the state
* reached after feeding CC to the cipher.
* @param cc_p
* @param div_key_p
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) {
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,
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
* MAC response.
* @param _init - precalculated cipher state
* @param nr - the reader challenge
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p) {
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;
}

51
armsrc/optimized_cipher.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef OPTIMIZED_CIPHER_H
#define OPTIMIZED_CIPHER_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
/**
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
* consisting of the following four components:
* 1. the left register l = (l 0 . . . l 7 ) F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) F 8/2 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/** The reader MAC is MAC(key, CC * NR )
**/
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
/**
* The tag MAC is MAC(key, CC * NR * 32x0))
*/
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]);
/**
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
* two functions, since the first 8 bytes are known, we can pre-calculate the state
* reached after feeding CC to the cipher.
* @param cc_p
* @param div_key_p
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
/**
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
* MAC response.
* @param _init - precalculated cipher state
* @param nr - the reader challenge
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p);
#endif // OPTIMIZED_CIPHER_H

505
armsrc/pcf7931.c Normal file
View file

@ -0,0 +1,505 @@
#include "pcf7931.h"
#define T0_PCF 8 //period for the pcf7931 in us
#define ALLOC 16
int DemodPCF7931(uint8_t **outBlocks) {
uint8_t bits[256] = {0x00};
uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr();
int GraphTraceLen = BigBuf_max_traceLen();
if ( GraphTraceLen > 18000 )
GraphTraceLen = 18000;
int i, j, lastval, bitidx, half_switch;
int clock = 64;
int tolerance = clock / 8;
int pmc, block_done;
int lc, warnings = 0;
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);
lmin = 64;
lmax = 192;
i = 2;
/* Find first local max/min */
if(dest[1] > dest[0]) {
while(i < GraphTraceLen) {
if( !(dest[i] > dest[i-1]) && dest[i] > lmax)
break;
i++;
}
dir = 0;
}
else {
while(i < GraphTraceLen) {
if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
break;
i++;
}
dir = 1;
}
lastval = i++;
half_switch = 0;
pmc = 0;
block_done = 0;
for (bitidx = 0; i < GraphTraceLen; i++)
{
if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin))
{
lc = i - lastval;
lastval = i;
// Switch depending on lc length:
// Tolerance is 1/8 of clock rate (arbitrary)
if (ABS(lc-clock/4) < tolerance) {
// 16T0
if((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128+127+16+32+33+16)-1;
lastval = i;
pmc = 0;
block_done = 1;
}
else {
pmc = i;
}
} else if (ABS(lc-clock/2) < tolerance) {
// 32TO
if((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128+127+16+32+33)-1;
lastval = i;
pmc = 0;
block_done = 1;
}
else if(half_switch == 1) {
bits[bitidx++] = 0;
half_switch = 0;
}
else
half_switch++;
} else if (ABS(lc-clock) < tolerance) {
// 64TO
bits[bitidx++] = 1;
} else {
// Error
warnings++;
if (warnings > 10)
{
Dbprintf("Error: too many detection errors, aborting...");
return 0;
}
}
if(block_done == 1) {
if(bitidx == 128) {
for(j=0; j<16; j++) {
blocks[num_blocks][j] = 128*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;
}
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;
}
void ReadPCF7931() {
uint8_t Blocks[8][17];
uint8_t tmpBlocks[4][16];
int i, j, ind, ind2, n;
int num_blocks = 0;
int max_blocks = 8;
int ident = 0;
int error = 0;
int tries = 0;
memset(Blocks, 0, 8*17*sizeof(uint8_t));
do {
memset(tmpBlocks, 0, 4*16*sizeof(uint8_t));
n = DemodPCF7931((uint8_t**)tmpBlocks);
if(!n)
error++;
if(error==10 && num_blocks == 0) {
Dbprintf("Error, no tag or bad tag");
return;
}
else if (tries==20 || error==10) {
Dbprintf("Error reading the tag");
Dbprintf("Here is the partial content");
goto end;
}
for(i=0; i<n; i++)
Dbprintf("(dbg) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
tmpBlocks[i][0], tmpBlocks[i][1], tmpBlocks[i][2], tmpBlocks[i][3], tmpBlocks[i][4], tmpBlocks[i][5], tmpBlocks[i][6], tmpBlocks[i][7],
tmpBlocks[i][8], tmpBlocks[i][9], tmpBlocks[i][10], tmpBlocks[i][11], tmpBlocks[i][12], tmpBlocks[i][13], tmpBlocks[i][14], tmpBlocks[i][15]);
if(!ident) {
for(i=0; i<n; i++) {
if(IsBlock0PCF7931(tmpBlocks[i])) {
// Found block 0 ?
if(i < n-1 && IsBlock1PCF7931(tmpBlocks[i+1])) {
// Found block 1!
// \o/
ident = 1;
memcpy(Blocks[0], tmpBlocks[i], 16);
Blocks[0][ALLOC] = 1;
memcpy(Blocks[1], tmpBlocks[i+1], 16);
Blocks[1][ALLOC] = 1;
max_blocks = MAX((Blocks[1][14] & 0x7f), Blocks[1][15]) + 1;
// Debug print
Dbprintf("(dbg) Max blocks: %d", max_blocks);
num_blocks = 2;
// Handle following blocks
for(j=i+2, ind2=2; j!=i; j++, ind2++, num_blocks++) {
if(j==n) j=0;
if(j==i) break;
memcpy(Blocks[ind2], tmpBlocks[j], 16);
Blocks[ind2][ALLOC] = 1;
}
break;
}
}
}
}
else {
for(i=0; i<n; i++) { // Look for identical block in known blocks
if(memcmp(tmpBlocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { // Block is not full of 00
for(j=0; j<max_blocks; j++) {
if(Blocks[j][ALLOC] == 1 && !memcmp(tmpBlocks[i], Blocks[j], 16)) {
// Found an identical block
for(ind=i-1,ind2=j-1; ind >= 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<max_blocks; i++) {
if(Blocks[i][ALLOC]==1)
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
Blocks[i][0], Blocks[i][1], Blocks[i][2], Blocks[i][3], Blocks[i][4], Blocks[i][5], Blocks[i][6], Blocks[i][7],
Blocks[i][8], Blocks[i][9], Blocks[i][10], Blocks[i][11], Blocks[i][12], Blocks[i][13], Blocks[i][14], Blocks[i][15]);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
cmd_send(CMD_ACK,0,0,0,0,0);
}
/* 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;
//BUILD OF THE DATA FRAME
//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<<u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else{ // bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//byte address on 4 bits
Dbprintf("Byte address : %02x", byte);
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
Dbprintf("Data : %02x", data);
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);
}
/* 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;
Dbprintf("Sending data frame...");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
LED_A_ON();
// steal this pin from the SSP and use it to control the modulation
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
//initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (0x1 << 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;
// 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);
}
/* 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 à 1
if( AddBitPCF7931(1, tab, l, p)==1) return 1;
} else { //bit à 0
if (AddBitPCF7931(0, tab, l, p)==1) return 1;
}
}
return 0;
}
/* Add a bits for building the data frame of PCF7931 tags
* @param b : bit to add
* @param tab : array of the data frame
* @param l : offset on low pulse width
* @param p : offset on low pulse positioning
*/
bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
uint8_t u = 0;
//we put the cursor at the last value of the array
for ( u = 0; tab[u] != 0; u += 3 ) { }
if ( b == 1 ) { //add a bit 1
if ( u == 0 )
tab[u] = 34 * T0_PCF + p;
else
tab[u] = 34 * T0_PCF + tab[u-1] + p;
tab[u+1] = 6 * T0_PCF + tab[u] + l;
tab[u+2] = 88 * T0_PCF + tab[u+1] - l - p;
return 0;
} else { //add a bit 0
if ( u == 0 )
tab[u] = 98 * T0_PCF + p;
else
tab[u] = 98 * T0_PCF + tab[u-1] + p;
tab[u+1] = 6 * T0_PCF + tab[u] + l;
tab[u+2] = 24 * T0_PCF + tab[u+1] - l - p;
return 0;
}
return 1;
}
/* Add a custom pattern in the data frame
* @param a : delay of the first high pulse
* @param b : delay of the low pulse
* @param c : delay of the last high pulse
* @param tab : array of the data frame
*/
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab){
uint32_t u = 0;
for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array
tab[u] = (u == 0) ? a : a + tab[u-1];
tab[u+1] = b + tab[u];
tab[u+2] = c + tab[u+1];
return 0;
}

20
armsrc/pcf7931.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef __PCF7931_H
#define __PCF7931_H
#include "proxmark3.h"
#include "apps.h"
#include "lfsampling.h"
#include "pcf7931.h"
#include "string.h"
int DemodPCF7931(uint8_t **outBlocks);
int IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block);
void ReadPCF7931();
void SendCmdPCF7931(uint32_t * tab);
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);
bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p);
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab);
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data);
#endif

View file

@ -33,23 +33,14 @@
*
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
*/
#include <stddef.h>
#include <stdarg.h>
#include "printf.h"
#include "util.h"
#include "string.h"
typedef uint32_t uintmax_t;
typedef int32_t intmax_t;
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef unsigned short u_short;
typedef unsigned long long u_quad_t;
typedef long long quad_t;
typedef unsigned long u_long;
typedef unsigned short u_short;
typedef int ssize_t;
#define NBBY 8 /* number of bits in a byte */
@ -431,7 +422,6 @@ 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);

View file

@ -12,6 +12,8 @@
#define __PRINTF_H
#include <stdarg.h>
#include <stddef.h>
#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)));

View file

@ -9,25 +9,76 @@
// with the linker script.
//-----------------------------------------------------------------------------
#ifndef __START_H
#define __START_H
#include "proxmark3.h"
#include "apps.h"
#include "zlib.h"
#include "BigBuf.h"
static uint8_t *next_free_memory;
extern struct common_area common_area;
extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size)
{
uint8_t *allocated_memory;
allocated_memory = next_free_memory;
next_free_memory += items*size;
return allocated_memory;
}
static void inflate_free(voidpf opaque, voidpf address)
{
// nothing to do
}
static void uncompress_data_section(void)
{
z_stream data_section;
next_free_memory = BigBuf_get_addr();
// initialize zstream structure
data_section.next_in = (uint8_t *) &__data_src_start__;
data_section.avail_in = &__data_end__ - &__data_start__; // uncompressed size. Wrong but doesn't matter.
data_section.next_out = (uint8_t *) &__data_start__;
data_section.avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct.
data_section.zalloc = &inflate_malloc;
data_section.zfree = &inflate_free;
data_section.opaque = NULL;
// initialize zlib for inflate
inflateInit2(&data_section, 15);
// uncompress data segment to RAM
inflate(&data_section, Z_FINISH);
// save the size of the compressed data section
common_area.arg1 = data_section.total_in;
}
extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__;
void __attribute__((section(".startos"))) Vector(void)
{
/* Stack should have been set up by the bootloader */
char *src, *dst, *end;
// char *src;
char *dst, *end;
uncompress_data_section();
/* Set up (that is: clear) BSS. */
dst = &__bss_start__;
end = &__bss_end__;
while(dst < end) *dst++ = 0;
/* Set up data segment: Copy from flash to ram */
src = &__data_src_start__;
dst = &__data_start__;
end = &__data_end__;
while(dst < end) *dst++ = *src++;
// Set up data segment: Copy from flash to ram
// src = &__data_src_start__;
// dst = &__data_start__;
// end = &__data_end__;
// while(dst < end) *dst++ = *src++;
AppMain();
}
#endif

View file

@ -1,27 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 Hector Martin "marcan" <marcan@marcansoft.com>
//
// 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.
//-----------------------------------------------------------------------------
// Replacement stdint.h because GCC doesn't come with it yet (C99)
//-----------------------------------------------------------------------------
#ifndef __STDINT_H
#define __STDINT_H
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
typedef long long int int64_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
typedef int intptr_t;
typedef unsigned int uintptr_t;
#endif /* __STDINT_H */

View file

@ -7,11 +7,9 @@
//-----------------------------------------------------------------------------
// Common string.h functions
//-----------------------------------------------------------------------------
#include "string.h"
#include <stdint.h>
void *memcpy(void *dest, const void *src, int len)
RAMFUNC void *memcpy(void *dest, const void *src, int len)
{
uint8_t *d = dest;
const uint8_t *s = src;
@ -33,7 +31,7 @@ void *memset(void *dest, int c, int len)
return dest;
}
int memcmp(const void *av, const void *bv, int len)
RAMFUNC int memcmp(const void *av, const void *bv, int len)
{
const uint8_t *a = av;
const uint8_t *b = bv;
@ -48,6 +46,11 @@ int memcmp(const void *av, const void *bv, int len)
return 0;
}
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;

View file

@ -12,14 +12,16 @@
#ifndef __STRING_H
#define __STRING_H
#include <common.h>
int strlen(const char *str);
void *memcpy(void *dest, const void *src, int len);
RAMFUNC void *memcpy(void *dest, const void *src, int len);
void *memset(void *dest, int c, int len);
int memcmp(const void *av, const void *bv, int len);
RAMFUNC int memcmp(const void *av, const void *bv, int len);
void memxor(uint8_t * dest, uint8_t * src, size_t len);
char *strncat(char *dest, const char *src, unsigned int n);
char *strcat(char *dest, const char *src);
void strreverse(char s[]);
void itoa(int n, char s[]);
#endif /* __STRING_H */
#endif /* __STRING_H */

229
armsrc/ticks.c Normal file
View file

@ -0,0 +1,229 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Sept 2005
// Iceman, Sept 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.
//-----------------------------------------------------------------------------
// Timers, Clocks functions used in LF or Legic where you would need detailed time.
//-----------------------------------------------------------------------------
#include "ticks.h"
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayUs(int us) {
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
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
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);
}
// -------------------------------------------------------------------------
// timer lib
// -------------------------------------------------------------------------
// test procedure:
//
// 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%
}
/*
* Get the current count.
*/
uint32_t RAMFUNC GetTickCount(void){
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
}
// -------------------------------------------------------------------------
// 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;
// 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;
}
// -------------------------------------------------------------------------
// 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
// 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 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
// 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).
// 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);
}
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;
}
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks
// -------------------------------------------------------------------------
void StartTicks(void){
//initialization of the timer
// tc1 is higher 0xFFFF0000
// tc0 is lower 0x0000FFFF
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_TC0->TC_CCR = AT91C_TC_CLKDIS;
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 = 0;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from TC0
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;
// wait until timer becomes zero.
while (AT91C_BASE_TC1->TC_CV > 0);
}
// 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 += GET_TICKS;
while (GET_TICKS < ticks);
}
// Wait / Spindelay in us (microseconds)
// 1us = 1.5ticks.
void WaitUS(uint16_t us){
if ( us == 0 ) return;
WaitTicks( (uint32_t)us * 3/2 );
}
void WaitMS(uint16_t ms){
if (ms == 0) return;
WaitTicks( (uint32_t)ms * 1500 );
}
// Starts Clock and waits until its reset
void ResetTicks(void){
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_TC1->TC_CV > 0);
}
void ResetTimer(AT91PS_TC timer){
timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while(timer->TC_CV > 0) ;
}
// stop clock
void StopTicks(void){
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
}

48
armsrc/ticks.h Normal file
View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Aug 2005
// Iceman, Sept 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.
//-----------------------------------------------------------------------------
// Timers, Clocks functions used in LF or Legic where you would need detailed time.
//-----------------------------------------------------------------------------
#ifndef __TICKS_H
#define __TICKS_H
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#include "apps.h"
#include "proxmark3.h"
#ifndef GET_TICKS
# define GET_TICKS (uint32_t)((AT91C_BASE_TC1->TC_CV << 16) | AT91C_BASE_TC0->TC_CV)
#endif
void SpinDelay(int ms);
void SpinDelayUs(int us);
void StartTickCount(void);
uint32_t RAMFUNC GetTickCount(void);
void StartCountUS(void);
uint32_t RAMFUNC GetCountUS(void);
void ResetUSClock(void);
void SpinDelayCountUs(uint32_t us);
//uint32_t RAMFUNC GetDeltaCountUS(void);
void StartCountSspClk();
void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
extern void StartTicks(void);
extern void WaitTicks(uint32_t ticks);
extern void WaitUS(uint16_t us);
extern void WaitMS(uint16_t ms);
extern void ResetTicks();
extern void ResetTimer(AT91PS_TC timer);
extern void StopTicks(void);
#endif

77
armsrc/tlv.c Normal file
View file

@ -0,0 +1,77 @@
#include <tlv.h>
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;
}

33
armsrc/tlv.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef __TLV_H
#define __TLV_H
#include <stdint.h>
#include <string.h>
#include <stddef.h>
//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

View file

@ -7,46 +7,121 @@
//-----------------------------------------------------------------------------
// Utility functions used in many places, not specific to any piece of code.
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "util.h"
#include "string.h"
#include "apps.h"
size_t nbytes(size_t nbits) {
return (nbits/8)+((nbits%8)>0);
return (nbits >> 3)+((nbits % 8) > 0);
}
uint32_t SwapBits(uint32_t value, int nrbits) {
int i;
uint32_t newvalue = 0;
for(i = 0; i < nrbits; i++) {
newvalue ^= ((value >> i) & 1) << (nrbits - 1 - i);
/*
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 newvalue;
return v;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{
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 bytes_to_num(uint8_t* src, size_t len) {
uint64_t num = 0;
while (len--)
{
while (len--) {
num = (num << 8) | (*src);
src++;
}
return num;
}
void LEDsoff()
{
// 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];
}
//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;
case 'a':
case 'A': return 10; break;
case 'b':
case 'B': return 11; break;
case 'c':
case 'C': return 12; break;
case 'd':
case 'D': return 13; break;
case 'e':
case 'E': return 14; break;
case 'f':
case 'F': return 15; break;
default:
return 0;
}
}
void LEDsoff() {
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
@ -54,8 +129,7 @@ void LEDsoff()
}
// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8]
void LED(int led, int ms)
{
void LED(int led, int ms) {
if (led & LED_RED)
LED_C_ON();
if (led & LED_ORANGE)
@ -80,13 +154,11 @@ void LED(int led, int ms)
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)
{
int BUTTON_CLICKED(int ms) {
// Up to 500ms in between clicks to mean a double click
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
@ -148,8 +220,7 @@ int BUTTON_CLICKED(int ms)
}
// Determine if a button is held down
int BUTTON_HELD(int ms)
{
int BUTTON_HELD(int ms) {
// If button is held for one second
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
@ -186,206 +257,36 @@ int BUTTON_HELD(int ms)
return BUTTON_ERROR;
}
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayUs(int us)
{
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);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
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);
}
/* Similar to FpgaGatherVersion this formats stored version information
* into a string representation. It takes a pointer to the struct version_information,
* verifies the magic properties, then stores a formatted string, prefixed by
* prefix in dst.
*/
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information)
{
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);
if(v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information", len - strlen(dst) - 1);
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", len - strlen(dst) - 1);
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", len - strlen(dst) - 1);
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) {
if (v->clean == 0) {
strncat(dst, "-unclean", len - strlen(dst) - 1);
} else if(v->clean == 2) {
} 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);
}
// -------------------------------------------------------------------------
// timer lib
// -------------------------------------------------------------------------
// test procedure:
//
// ti = GetTickCount();
// SpinDelay(1000);
// ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
void StartTickCount()
{
// must be 0x40, but on my cpu - included divider is optimal
// 0x20 - 1 ms / bit
// 0x40 - 2 ms / bit
AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST + 0x001D; // was 0x003B
}
/*
* Get the current count.
*/
uint32_t RAMFUNC GetTickCount(){
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
}
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS()
{
AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14);
// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0;
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
// fast clock
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz)/32 -- tick=1.5mks
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_BASE_TC1->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TCB->TCB_BCR = 1;
}
uint32_t RAMFUNC GetCountUS(){
return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
}
static uint32_t GlobalUsCounter = 0;
uint32_t RAMFUNC GetDeltaCountUS(){
uint32_t g_cnt = GetCountUS();
uint32_t g_res = g_cnt - GlobalUsCounter;
GlobalUsCounter = g_cnt;
return g_res;
}
// -------------------------------------------------------------------------
// Timer for iso14443 commands. Uses ssp_clk from FPGA
// -------------------------------------------------------------------------
void StartCountSspClk()
{
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
// 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 TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP; // just count
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2
//
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14446 mode, otherwise the frame signal would not be present
//
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to 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).
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before
// we can use the counter.
while (AT91C_BASE_TC0->TC_CV < 0xFFF0);
}
uint32_t RAMFUNC GetCountSspClk(){
uint32_t tmp_count;
tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
if ((tmp_count & 0x0000ffff) == 0) { //small chance that we may have missed an increment in TC2
return (AT91C_BASE_TC2->TC_CV << 16);
}
else {
return tmp_count;
}
}

View file

@ -11,9 +11,11 @@
#ifndef __UTIL_H
#define __UTIL_H
#include <stddef.h>
#include <stdint.h>
#include <common.h>
#include "common.h"
#include "proxmark3.h"
#include "string.h"
#include "BigBuf.h"
#include "ticks.h"
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
@ -27,27 +29,33 @@
#define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
#ifndef BSWAP_16
# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
#endif
#ifndef BITMASK
# define BITMASK(X) (1 << (X))
#endif
#ifndef ARRAYLEN
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
#endif
size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits);
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 SpinDelay(int ms);
void SpinDelayUs(int us);
void LED(int led, int ms);
void LEDsoff();
int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms);
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
void StartTickCount();
uint32_t RAMFUNC GetTickCount();
void StartCountUS();
uint32_t RAMFUNC GetCountUS();
uint32_t RAMFUNC GetDeltaCountUS();
void StartCountSspClk();
uint32_t RAMFUNC GetCountSspClk();
#endif

281
armsrc/vtsend.c Normal file
View file

@ -0,0 +1,281 @@
/**
* @file vtsend.c
* @author CuBeatSystems
* @author Shinichiro Nakamura
* @copyright
* ===============================================================
* Natural Tiny Shell (NT-Shell) Version 0.3.1
* ===============================================================
* Copyright (c) 2010-2016 Shinichiro Nakamura
*
* 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.
*/
#include "vtsend.h"
#include "apps.h"
#define ESC (0x1B)
//#define UART_WRITE(P, BUF, SIZ) (P)->uart_write(BUF, SIZ, (P)->extobj)
#define UART_WRITE(BUF) DbprintfEx(FLAG_RAWPRINT, "%s", BUF)
int vtsend_init(vtsend_t *p, VTSEND_SERIAL_WRITE uart_write, void *extobj) {
p->uart_write = uart_write;
p->extobj = extobj;
return 0;
}
int vtsend_cursor_position(vtsend_t *p, const int column, const int line) {
char buf[1 + 8];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (line / 10);
buf[3] = '0' + (line % 10);
buf[4] = ';';
buf[5] = '0' + (column / 10);
buf[6] = '0' + (column % 10);
buf[7] = 'H';
buf[8] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_up(vtsend_t *p, const int n) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (n / 10);
buf[3] = '0' + (n % 10);
buf[4] = 'A';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_down(vtsend_t *p, const int n) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (n / 10);
buf[3] = '0' + (n % 10);
buf[4] = 'B';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_forward(vtsend_t *p, const int n) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (n / 10);
buf[3] = '0' + (n % 10);
buf[4] = 'C';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_backward(vtsend_t *p, const int n) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (n / 10);
buf[3] = '0' + (n % 10);
buf[4] = 'D';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_position_save(vtsend_t *p) {
char buf[1 + 3];
buf[0] = ESC;
buf[1] = '[';
buf[2] = 's';
buf[3] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_cursor_position_restore(vtsend_t *p) {
char buf[1 + 3];
buf[0] = ESC;
buf[1] = '[';
buf[2] = 'u';
buf[3] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_erase_display(vtsend_t *p) {
char buf[1 + 4];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '2';
buf[3] = 'J';
buf[4] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_erase_line(vtsend_t *p) {
char buf[1 + 4];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '2';
buf[3] = 'K';
buf[4] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_set_color_foreground(vtsend_t *p, const int color) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + ((30 + color) / 10);
buf[3] = '0' + ((30 + color) % 10);
buf[4] = 'm';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_set_color_background(vtsend_t *p, const int color) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + ((40 + color) / 10);
buf[3] = '0' + ((40 + color) % 10);
buf[4] = 'm';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_set_attribute(vtsend_t *p, const int attr) {
char buf[1 + 5];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + ((attr) / 10);
buf[3] = '0' + ((attr) % 10);
buf[4] = 'm';
buf[5] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_set_scroll_region(vtsend_t *p, const int top, const int bottom) {
char buf[1 + 8];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '0' + (top / 10);
buf[3] = '0' + (top % 10);
buf[4] = ';';
buf[5] = '0' + (bottom / 10);
buf[6] = '0' + (bottom % 10);
buf[7] = 'r';
buf[8] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_set_cursor(vtsend_t *p, const int visible) {
if (visible) {
char buf[1 + 6];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '?';
buf[3] = '2';
buf[4] = '5';
buf[5] = 'h';
buf[6] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
} else {
char buf[1 + 6];
buf[0] = ESC;
buf[1] = '[';
buf[2] = '?';
buf[3] = '2';
buf[4] = '5';
buf[5] = 'l';
buf[6] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
}
return 0;
}
int vtsend_reset(vtsend_t *p) {
char buf[1 + 2];
buf[0] = ESC;
buf[1] = 'c';
buf[2] = '\0';
UART_WRITE(buf); // UART_WRITE(p, buf, sizeof(buf));
return 0;
}
int vtsend_draw_box(vtsend_t *p, const int x1, const int y1, const int x2, const int y2) {
int i;
vtsend_cursor_position(p, x1, y1);
for (i = x1; i <= x2; i++) {
UART_WRITE("-");
}
vtsend_cursor_position(p, x1, y2);
for (i = x1; i <= x2; i++) {
UART_WRITE("-");
}
for (i = y1; i <= y2; i++) {
vtsend_cursor_position(p, x1, i);
UART_WRITE("|");
vtsend_cursor_position(p, x2, i);
UART_WRITE("|");
}
return 0;
}
int vtsend_fill_box(vtsend_t *p, const int x1, const int y1, const int x2, const int y2) {
int i, j;
for (i = y1; i <= y2; i++) {
vtsend_cursor_position(p, x1, i);
for (j = x1; j <= x2; j++) {
UART_WRITE(" ");
}
}
return 0;
}

93
armsrc/vtsend.h Normal file
View file

@ -0,0 +1,93 @@
/**
* @file vtsend.h
* @author CuBeatSystems
* @author Shinichiro Nakamura
* @copyright
* ===============================================================
* Natural Tiny Shell (NT-Shell) Version 0.3.1
* ===============================================================
* Copyright (c) 2010-2016 Shinichiro Nakamura
*
* 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.
*/
#ifndef VTSEND_H
#define VTSEND_H
#define VTSEND_COLOR_BLACK (0)
#define VTSEND_COLOR_RED (1)
#define VTSEND_COLOR_GREEN (2)
#define VTSEND_COLOR_YELLOW (3)
#define VTSEND_COLOR_BLUE (4)
#define VTSEND_COLOR_MAGENTA (5)
#define VTSEND_COLOR_CYAN (6)
#define VTSEND_COLOR_WHITE (7)
#define VTSEND_ATTR_OFF (0)
#define VTSEND_ATTR_BOLD_ON (1)
#define VTSEND_ATTR_UNDERSCORE (4)
#define VTSEND_ATTR_BLINK_ON (5)
#define VTSEND_ATTR_REVERSE (7)
#define VTSEND_ATTR_CONCEALED_ON (8)
typedef int (*VTSEND_SERIAL_WRITE)(const char *buf, const int siz, void *extobj);
typedef struct {
VTSEND_SERIAL_WRITE uart_write;
void *extobj;
} vtsend_t;
#ifdef __cplusplus
extern "C" {
#endif
int vtsend_init(vtsend_t *p, VTSEND_SERIAL_WRITE uart_write, void *extobj);
int vtsend_cursor_position(vtsend_t *p, const int column, const int line);
int vtsend_cursor_up(vtsend_t *p, const int n);
int vtsend_cursor_down(vtsend_t *p, const int n);
int vtsend_cursor_forward(vtsend_t *p, const int n);
int vtsend_cursor_backward(vtsend_t *p, const int n);
int vtsend_cursor_position_save(vtsend_t *p);
int vtsend_cursor_position_restore(vtsend_t *p);
int vtsend_erase_display(vtsend_t *p);
int vtsend_erase_line(vtsend_t *p);
int vtsend_set_color_foreground(vtsend_t *p, const int color);
int vtsend_set_color_background(vtsend_t *p, const int color);
int vtsend_set_attribute(vtsend_t *p, const int attr);
int vtsend_set_scroll_region(vtsend_t *p, const int top, const int bottom);
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);
int vtsend_fill_box(
vtsend_t *p,
const int x1, const int y1, const int x2, const int y2);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -8,8 +8,12 @@
# 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 bootrom.c
THUMBSRC = cmd.c \
usb_cdc.c \
bootrom.c
ASMSRC = ram-reset.s flash-reset.s
VERSIONSRC = version.c
## There is a strange bug with the linker: Sometimes it will not emit the glue to call
## BootROM from ARM mode. The symbol is emitted, but the section will be filled with
@ -19,13 +23,17 @@ ASMSRC = ram-reset.s flash-reset.s
# THUMBSRC :=
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I.
APP_CFLAGS = -I. -fno-strict-aliasing -ffunction-sections -fdata-sections
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common
OBJS = $(OBJDIR)/bootrom.s19
# version.c should be remade on every compilation
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
all: $(OBJS)
tarbin: $(OBJS)

View file

@ -9,27 +9,26 @@
#include <proxmark3.h>
#include "usb_cdc.h"
#include "cmd.h"
//#include "usb_hid.h"
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);
}
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 void ConfigClocks(void)
{
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);
}
static void ConfigClocks(void) {
// we are using a 16 MHz crystal as the basis for everything
// slow clock runs at 32Khz typical regardless of crystal
// enable system clock and USB clock
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK | AT91C_PMC_UDP;
AT91C_BASE_PMC->PMC_SCER |= AT91C_PMC_PCK | AT91C_PMC_UDP;
// enable the clock to the following peripherals
AT91C_BASE_PMC->PMC_PCER =
@ -50,22 +49,21 @@ static void ConfigClocks(void)
PMC_MAIN_OSC_STARTUP_DELAY(8);
// wait for main oscillator to stabilize
while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS) )
;
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(0x50) |
//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) )
;
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
@ -73,184 +71,155 @@ static void ConfigClocks(void)
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) )
;
while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) ) {};
// 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) )
;
while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) ) {};
}
static void Fatal(void)
{
for(;;);
static void Fatal(void) {
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;
UsbCommand* c = (UsbCommand *)packet;
volatile uint32_t *p;
//if ( len != sizeof(UsbCommand)) Fatal();
if(len != sizeof(UsbCommand)) {
Fatal();
}
uint32_t arg0 = (uint32_t)c->arg[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;
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];
/* 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;
}
switch(c->cmd) {
case CMD_DEVICE_INFO: {
dont_ack = 1;
// c->cmd = CMD_DEVICE_INFO;
arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM |
DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH;
if(common_area.flags.osimage_present) {
arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT;
}
// UsbSendPacket(packet, len);
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);
// p = (volatile uint32_t *)&_flash_start;
for (size_t j=0; j<2; j++) {
for(i = 0+(64*j); i < 64+(64*j); i++) {
//p[i+60] = c->d.asDwords[i];
flash_mem[i] = c->d.asDwords[i];
}
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;
// c->cmd = CMD_NACK;
// UsbSendPacket(packet, len);
cmd_send(CMD_NACK,0,0,0,0,0);
} else {
uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE;
/* Translate address to flash page and do flash, update here for the 512k part */
AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY |
MC_FLASH_COMMAND_PAGEN(page_n) |
AT91C_MC_FCMD_START_PROG;
// arg0 = (address - ((uint32_t)flash_s));
}
// Wait until flashing of page finishes
uint32_t sr;
while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY));
if(sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) {
dont_ack = 1;
// c->cmd = CMD_NACK;
cmd_send(CMD_NACK,0,0,0,0,0);
// UsbSendPacket(packet, len);
}
}
} break;
case CMD_HARDWARE_RESET: {
// USB_D_PLUS_PULLUP_OFF();
usb_disable();
AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
} break;
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;
// c->cmd = CMD_NACK;
// UsbSendPacket(packet, len);
cmd_send(CMD_NACK,0,0,0,0,0);
}
}
} break;
default: {
Fatal();
} break;
}
if(!dont_ack) {
// c->cmd = CMD_ACK;
// UsbSendPacket(packet, len);
cmd_send(CMD_ACK,arg0,0,0,0,0);
}
if (!dont_ack)
cmd_send(CMD_ACK,arg0,0,0,0,0);
}
static void flash_mode(int externally_entered)
{
static void flash_mode(int externally_entered) {
start_addr = 0;
end_addr = 0;
bootrom_unlocked = 0;
byte_t rx[sizeof(UsbCommand)];
size_t rx_len;
byte_t rx[sizeof(UsbCommand)];
usb_enable();
for (volatile size_t i=0; i<0x100000; i++);
usb_enable();
// wait for reset to be complete?
for (volatile size_t i=0; i<0x100000; i++) {};
// UsbStart();
for(;;) {
WDT_HIT();
if (usb_poll()) {
rx_len = usb_read(rx,sizeof(UsbCommand));
if (rx_len) {
// DbpString("starting to flash");
UsbPacketReceived(rx,rx_len);
}
}
// UsbPoll(TRUE);
if(!externally_entered && !BUTTON_PRESS()) {
// 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_D_PLUS_PULLUP_OFF();
usb_disable();
usb_disable();
LED_B_ON();
AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
for(;;);
for(;;) {};
}
if(externally_entered && BUTTON_PRESS()) {
if (externally_entered && BUTTON_PRESS()) {
/* Let the user's button press override the automatic leave */
externally_entered = 0;
}
}
}
extern uint32_t _osimage_entry;
void BootROM(void)
{
void BootROM(void) {
//------------
// First set up all the I/O pins; GPIOs configured directly, other ones
// just need to be assigned to the appropriate peripheral.
@ -292,16 +261,20 @@ void BootROM(void)
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();
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);
// Initialize all system clocks
ConfigClocks();
@ -309,36 +282,37 @@ void BootROM(void)
LED_A_ON();
int common_area_present = 0;
switch(AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_RSTTYP) {
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) {
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){
if (!common_area_present){
/* Common area not ok, initialize it */
int i; for(i=0; i<sizeof(common_area); i++) { /* Makeshift memset, no need to drag util.c into this */
int i;
/* Makeshift memset, no need to drag util.c into this */
for(i=0; i<sizeof(common_area); i++)
((char*)&common_area)[i] = 0;
}
common_area.magic = COMMON_AREA_MAGIC;
common_area.version = 1;
common_area.flags.bootrom_present = 1;
}
common_area.flags.bootrom_present = 1;
if(common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) {
if (common_area.command == COMMON_AREA_COMMAND_ENTER_FLASH_MODE) {
common_area.command = COMMON_AREA_COMMAND_NONE;
flash_mode(1);
} else if(BUTTON_PRESS()) {
} else if (BUTTON_PRESS()) {
flash_mode(0);
} else if(_osimage_entry == 0xffffffffU) {
} else if (_osimage_entry == 0xffffffffU) {
flash_mode(1);
} else {
// jump to Flash address of the osimage entry point (LSBit set for thumb mode)

View file

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd ">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key> <string>English</string>
<key>CFBundleIdentifier</key> <string>org.proxmark</string>
<key>CFBundleIconFile</key> <string></string>
<key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
<key>CFBundlePackageType</key> <string>KEXT</string>
<key>CFBundleSignature</key> <string>????</string>
<key>CFBundleVersion</key> <string>1.0.0</string>
<key>IOKitPersonalities</key>
<dict>
<key>Proxmark3</key>
<dict>
<key>CFBundleIdentifier</key><string>com.apple.kernel.iokit</string>
<key>IOClass</key><string>IOService</string>
<key>IOProviderClass</key><string>IOUSBInterface</string>
<key>bConfigurationValue</key> <integer>1</integer>
<key>bInterfaceNumber</key> <integer>0</integer>
<key>idProduct</key><integer>19343</integer>
<key>idVendor</key><integer>39620</integer>
</dict>
</dict>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.iokit.IOUSBFamily</key><string>1.8</string>
</dict>
</dict>
</plist>

View file

@ -3,70 +3,148 @@
# at your option, any later version. See the LICENSE.txt file for the text of
# the license.
#-----------------------------------------------------------------------------
include ../common/Makefile.common
# reveng will compile without macros, but these may be useful:
# Add -DBMPMACRO to use bitmap size constant macros (edit config.h)
# Add -DNOFORCE to disable the -F switch
# Add -DPRESETS to compile with preset models (edit config.h)
CC=gcc
CXX=g++
#COMMON_FLAGS = -m32
CC = gcc
CXX = g++
LD = g++
TAR = tar
TARFLAGS = -C .. --ignore-failed-read -rvf
RM = rm -f
MV = mv
VPATH = ../common
ENV_LDFLAGS := $(LDFLAGS)
ENV_CFLAGS := $(CFLAGS)
VPATH = ../common ../zlib ../uart
OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a
LDFLAGS = $(COMMON_FLAGS)
CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
LUALIB = ../liblua/liblua.a
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
CXXFLAGS = -I../include -Wall -O3
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
MOC = $(QTDIR)/bin/moc
LUAPLATFORM = mingw
else ifeq ($(platform),Darwin)
#CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers
#QTLDLIBS = -framework QtGui -framework QtCore
CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -F/opt/local/Library/Frameworks -framework QtGui -framework QtCore
MOC = moc
LUAPLATFORM = macosx
platform = $(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
LUAPLATFORM = mingw
else
ifeq ($(platform),Darwin)
LUAPLATFORM = macosx
else
CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4
QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
MOC = $(shell pkg-config --variable=moc_location QtCore)
LDLIBS += -ldl
LUALIB += -ldl
LDLIBS += -ltermcap -lncurses
LUAPLATFORM = linux
endif
endif
# Below is a variant you can use if you have problems compiling with QT5 on ubuntu. see http://www.proxmark.org/forum/viewtopic.php?id=1661 for more info.
#MOC = /usr/lib/x86_64-linux-gnu/qt4/bin/moc
LUAPLATFORM = linux
# Check for correctly configured Qt5
QTINCLUDES = $(shell pkg-config --cflags Qt5Core Qt5Widgets 2>/dev/null)
QTLDLIBS = $(shell pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null)
MOC = $(shell pkg-config --variable=host_bins Qt5Core)/moc
UIC = $(shell pkg-config --variable=host_bins Qt5Core)/uic
ifeq ($(QTINCLUDES), )
# if Qt5 not found check for correctly configured Qt4
QTINCLUDES = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null)
QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null)
MOC = $(shell pkg-config --variable=moc_location QtCore)
UIC = $(shell pkg-config --variable=uic_location QtCore)
else
CXXFLAGS += -std=c++11 -fPIC
endif
ifeq ($(QTINCLUDES), )
# if both pkg-config commands failed, search in common places
ifneq ($(QTDIR), )
QTINCLUDES = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui
QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4
ifneq ($(wildcard $(QTDIR)/include/QtWidgets),)
QTINCLUDES += -I$(QTDIR)/include/QtWidgets
QTLDLIBS = -L$(QTDIR)/lib -lQt5Widgets -lQt5Gui -lQt5Core
CXXFLAGS += -std=c++11 -fPIC
endif
MOC = $(QTDIR)/bin/moc
UIC = $(QTDIR)/bin/uic
endif
endif
ifneq ($(QTLDLIBS),)
QTGUI = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o
CFLAGS += -DHAVE_GUI
LINK.o = $(LINK.cpp)
QTGUIOBJS = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o
CFLAGS += -DHAVE_GUI
else
QTGUI = guidummy.o
QTGUIOBJS = $(OBJDIR)/guidummy.o
endif
CORESRCS = uart.c \
util.c \
sleep.c
# 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
CMDSRCS = nonce2key/crapto1.c\
nonce2key/crypto1.c\
nonce2key/nonce2key.c\
mifarehost.c\
crc16.c \
iso14443crc.c \
iso15693tools.c \
data.c \
graph.c \
CORESRCS = uart_posix.c \
uart_win32.c \
ui.c \
util.c \
util_posix.c \
scandir.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 \
@ -74,77 +152,196 @@ CMDSRCS = nonce2key/crapto1.c\
cmdhflegic.c \
cmdhficlass.c \
cmdhfmf.c \
cmdhfmfu.c \
cmdhfmfhard.c \
hardnested/hardnested_bruteforce.c \
cmdhfmfdes.c \
cmdhftopaz.c \
cmdhffelica.c \
cmdhw.c \
cmdlf.c \
cmdlfhid.c \
cmdlfio.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 \
cmdlft55xx.c \
cmdlfpcf7931.c\
pm3_binlib.c\
scripting.c\
cmdscript.c\
pm3_bitlib.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
cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), )
MULTIARCHSRCS = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c
endif
ifneq ($(findstring amd64, $(cpu_arch)), )
MULTIARCHSRCS = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c
endif
ifeq ($(MULTIARCHSRCS), )
CMDSRCS += hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c
endif
ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c
ZLIBFLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED
#-DDEBUG -Dverbose=1
QTGUISRCS = proxgui.cpp proxguiqt.cpp proxguiqt.moc.cpp guidummy.cpp
COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
CMDOBJS = $(CMDSRCS:%.c=$(OBJDIR)/%.o)
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)
RM = rm -f
BINS = proxmark3 flasher #snooper cli
CLEAN = cli cli.exe flasher flasher.exe proxmark3 proxmark3.exe snooper snooper.exe $(CMDOBJS) $(OBJDIR)/*.o *.o *.moc.cpp
SUPPORTS_AVX512 := $(shell echo | gcc -E -mavx512f - > /dev/null 2>&1 && echo "True" )
HARD_SWITCH_NOSIMD = -mno-mmx -mno-sse2 -mno-avx -mno-avx2
HARD_SWITCH_MMX = -mmmx -mno-sse2 -mno-avx -mno-avx2
HARD_SWITCH_SSE2 = -mmmx -msse2 -mno-avx -mno-avx2
HARD_SWITCH_AVX = -mmmx -msse2 -mavx -mno-avx2
HARD_SWITCH_AVX2 = -mmmx -msse2 -mavx -mavx2
HARD_SWITCH_AVX512 = -mmmx -msse2 -mavx -mavx2 -mavx512f
ifeq "$(SUPPORTS_AVX512)" "True"
HARD_SWITCH_NOSIMD += -mno-avx512f
HARD_SWITCH_MMX += -mno-avx512f
HARD_SWITCH_SSE2 += -mno-avx512f
HARD_SWITCH_AVX += -mno-avx512f
HARD_SWITCH_AVX2 += -mno-avx512f
MULTIARCHOBJS += $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX512.o)
endif
BINS = proxmark3 flasher fpga_compress
WINBINS = $(patsubst %, %.exe, $(BINS))
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua lualibs/mf_default_keys.lua
# need to assign dependancies to build these first...
all: lua_build $(BINS)
all-static: LDLIBS:=-static $(LDLIBS)
all-static: snooper cli flasher
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 $@
proxmark3: LDLIBS+=$(QTLDLIBS)
proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUI)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
snooper: $(OBJDIR)/snooper.o $(COREOBJS) $(CMDOBJS) $(OBJDIR)/guidummy.o
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
cli: $(OBJDIR)/cli.o $(COREOBJS) $(CMDOBJS) $(OBJDIR)/guidummy.o
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@
$(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
fpga_compress: $(OBJDIR)/fpga_compress.o $(ZLIBOBJS)
$(LD) $(LDFLAGS) $(ZLIBFLAGS) $^ $(LDLIBS) -o $@
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
proxgui.cpp: ui/ui_overlays.h
proxguiqt.moc.cpp: proxguiqt.h
$(MOC) -o$@ $^
ui/ui_overlays.h: ui/overlays.ui
$(UIC) $^ > $@
lualibs/usb_cmd.lua: ../include/usb_cmd.h
awk -f usb_cmd_h2lua.awk $^ > $@
lualibs/mf_default_keys.lua : default_keys.dic
awk -f default_keys_dic2lua.awk $^ > $@
clean:
$(RM) $(CLEAN)
cd ../liblua && make clean
tarbin: $(BINS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%)
# must be run as root
install_kext: Info.plist
mkdir -p /System/Library/Extensions/Proxmark3.kext/Contents
cp Info.plist /System/Library/Extensions/Proxmark3.kext/Contents
chown -R root:wheel /System/Library/Extensions/Proxmark3.kext
chmod 755 /System/Library/Extensions/Proxmark3.kext /System/Library/Extensions/Proxmark3.kext/Contents
chmod 644 /System/Library/Extensions/Proxmark3.kext/Contents/Info.plist
rm -rf /System/Library/Caches/com.apple.kext.caches
touch /System/Library/Extensions
@echo "*** You may need to reboot for the kext to take effect."
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
lua_build:
@echo Compiling liblua, using platform $(LUAPLATFORM)
cd ../liblua && make $(LUAPLATFORM)
.PHONY: all clean
# easy printing of MAKE VARIABLES
print-%: ; @echo $* = $($*)
$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_NOSIMD) -c -o $@ $<
$(OBJDIR)/%_MMX.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_MMX) -c -o $@ $<
$(OBJDIR)/%_SSE2.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $<
$(OBJDIR)/%_AVX.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $<
$(OBJDIR)/%_AVX2.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $<
$(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $<
%.o: %.c
$(OBJDIR)/%.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $<
$(POSTCOMPILE)
%.o: %.cpp
$(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d
$(CXX) $(DEPFLAGS) $(CXXFLAGS) $(QTINCLUDES) -c -o $@ $<
$(POSTCOMPILE)
#$(CMDOBJS) $(COREOBJS): $(notdir $(%.c)) %.d
# $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
# $(POSTCOMPILE)
#$(ZLIBOBJS): $(notdir $(%.c)) %.d
# $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $<
# $(POSTCOMPILE)
#$(QTGUIOBJS): $(notdir $(%.cpp)) %.d
# $(CXX) $(DEPFLAGS) $(CXXFLAGS) -c -o $@ $<
# $(POSTCOMPILE)
DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBSRCS) $(MULTIARCHSRCS)) \
$(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \
$(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d
$(DEPENDENCY_FILES): ;
.PRECIOUS: $(DEPENDENCY_FILES)
-include $(DEPENDENCY_FILES)

View file

@ -7,9 +7,9 @@
//-----------------------------------------------------------------------------
#include <stdio.h>
#include "sleep.h"
#include "util_posix.h"
#include "ui.h"
#include "proxusb.h"
//#include "proxusb.h"
#include "cmdmain.h"
#define HANDLE_ERROR if (error_occured) { \
@ -37,7 +37,7 @@ int main(int argc, char **argv)
return_on_error = 1;
while (1) {
while (!OpenProxmark(0)) { sleep(1); }
while (!OpenProxmark()) { sleep(1); }
while (1) {
UsbCommand cmdbuf;
CommandReceived(argv[1]);

906
client/cmdanalyse.c Normal file
View file

@ -0,0 +1,906 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2016 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.
//-----------------------------------------------------------------------------
// Analyse bytes commands
//-----------------------------------------------------------------------------
#include "cmdanalyse.h"
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] <bytes>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " <bytes> 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 <bytes> m <mask>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " v supress header");
PrintAndLogEx(NORMAL, " b <bytes> bytes to calc missing XOR in a LCR");
PrintAndLogEx(NORMAL, " m <mask> 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] <bytes>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " <bytes> 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] <bytes>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " <bytes> input bytes (14 hexsymbols)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " analyse nuid 11223344556677");
return 0;
}
int usage_analyse_a(void) {
PrintAndLogEx(NORMAL, "my personal garbage test command");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: analyse a [h] d <bytes>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " d <bytes> 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) {
uint8_t LRC = 0;
for (uint8_t i = 0; i < len; i++)
LRC ^= bytes[i];
return LRC;
}
/*
static uint16_t matrixadd ( uint8_t* bytes, uint8_t len){
-----------
0x9c | 1001 1100
0x97 | 1001 0111
0x72 | 0111 0010
0x5e | 0101 1110
-----------------
C32F 9d74
return 0;
}
*/
/*
static uint16_t shiftadd ( uint8_t* bytes, uint8_t len){
return 0;
}
*/
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;
return sum;
}
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) {
uint16_t sum = 0;
for (uint8_t i = 0; i < len; i++) {
sum += NIBBLE_LOW(bytes[i]);
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 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;
return sum;
}
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;
return sum;
}
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;
return sum;
}
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;
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 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;
return sum;
}
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) {
uint8_t sum = 0;
for (uint8_t i = 0; i < len; i++) {
sum -= NIBBLE_LOW(bytes[i]);
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);
}
// 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;
}
// 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;
}
// measuring LFSR maximum length
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);
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, " %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;
param_gethex_ex(Cmd, 0, data, &len);
if ( len%2 ) return usage_analyse_lcr();
len >>= 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) {
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;
if ( param_gethex(Cmd, 0, data, len)) {
free(data);
return usage_analyse_crc();
}
len >>= 1;
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));
//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)", 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)) );
// 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)) );
// 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)) );
// 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;
}
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;
}
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;
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
*/
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;
}
}
}
*/
//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)
// uid(6e442129) nt(8f699195) ks(00040f0f0305030e) nr(00000004)
//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);
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);
/*
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
};
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;
}
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();
/* 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;
}
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}
};
int CmdAnalyse(const char *Cmd) {
clearCommandBuffer();
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable);
return 0;
}

45
client/cmdanalyse.h Normal file
View file

@ -0,0 +1,45 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2016 iceman <iceman at ...>
//
// 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.
//-----------------------------------------------------------------------------
// Data and Graph commands
//-----------------------------------------------------------------------------
#ifndef CMDANALYSE_H__
#define CMDANALYSE_H__
#include <stdlib.h> //size_t
#include <string.h>
#include <unistd.h>
#include "cmdmain.h"
#include "proxmark3.h"
#include "ui.h" // PrintAndLog
#include "util.h"
#include "crc.h"
#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);
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

480
client/cmdcrc.c Normal file
View file

@ -0,0 +1,480 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2015 iceman <iceman at iuse.se>
//
// 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.
//-----------------------------------------------------------------------------
// CRC Calculations from the software reveng commands
//-----------------------------------------------------------------------------
#include "cmdcrc.h"
#define MAX_ARGS 20
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])) {
++beginIndex;
}
if(str[beginIndex] == '\0') {
break;
}
endIndex = beginIndex;
while (str[endIndex] && !isspace(str[endIndex])) {
++endIndex;
}
int len = endIndex - beginIndex;
char *tmp = calloc(len + 1, sizeof(char));
memcpy(tmp, &str[beginIndex], len);
arr[wordCnt++] = tmp;
beginIndex = endIndex;
if (wordCnt == maxWords)
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 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;
/* 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
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 (!plen(model.spoly))
palloc(&model.spoly, (unsigned long)width[0]);
else
width[0] = (uint8_t)plen(model.spoly);
/* special case if qpoly is zero, search to end of range */
if (!ptst(qpoly))
rflags &= ~R_HAVEQ;
/* 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();
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) {
/* 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 (!(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;
}
//-c || -v
//inModel = valid model name string - CRC-8
//inHexStr = input hex string to calculate crc on
//reverse = reverse calc option if true
//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;
char *string;
// stdin must be binary
#ifdef _WIN32
_setmode(STDIN_FILENO, _O_BINARY);
#endif /* _WIN32 */
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);
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);
}
// 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);
apoly = strtop(inHexStr, model.flags, ibperhx);
if (reverse)
prev(&apoly);
crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
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;
}
//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++);
//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;
}
// takes hex string in and searches for a matching result (hex string must include checksum)
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;
// these two arrays, must match preset size.
char *Models[NMODELS];
uint8_t width[NMODELS] = {0};
int count = 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);
char *outHex = calloc(dataLen-crcChars+1, sizeof(char));
memcpy(outHex, inHexStr, dataLen-crcChars);
// 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;
}

36
client/cmdcrc.h Normal file
View file

@ -0,0 +1,36 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2015 iceman <iceman at iuse.se>
//
// 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.
//-----------------------------------------------------------------------------
// CRC Calculations from the software reveng commands
//-----------------------------------------------------------------------------
#ifndef CMDCRC_H__
#define CMDCRC_H__
#ifdef _WIN32
# include <io.h>
# include <fcntl.h>
# ifndef STDIN_FILENO
# define STDIN_FILENO 0
# endif /* STDIN_FILENO */
#endif /* _WIN32 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "cmdmain.h"
#include "reveng/reveng.h"
#include "ui.h"
#include "util.h"
extern 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);
#endif

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