Compare commits

...

209 commits

Author SHA1 Message Date
pwpiwi
6116334485
Merge pull request #969 from pwpiwi/gcc10_fixes
Gcc10 fixes
2021-03-30 08:59:58 +02:00
pwpiwi
cbecb8a209 gcc10 compiler fixes:
- Check for availability of getenv_s() in argtable3.c
2021-03-18 08:25:16 +01:00
pwpiwi
d3f8d76d6c Fix gcc10 compiler warnings
- update argtable3 to latest versions
2021-03-18 08:23:17 +01:00
pwpiwi
8ac5d5cba1 Fix gcc10 compiler warnings
- fix attribute format for MINGW in tinycbor/cbor.h
- add pragma to prevent "unaligned pointer" warning in cmddata.c. We know what we are doing there.
- whitespace fixes
2021-01-29 08:26:33 +01:00
pwpiwi
ad326d84ad Fix gcc 10 link issues
- avoid linker error by providing string.[ch] in bootrom
2021-01-28 09:00:08 +01:00
pwpiwi
555fa19773
Cleanup armsrc/string.c and string.h (#964)
- remove unnecessary memxor(), strreverse(), and itoa() functions
- Use correct types in function declarations and definitions
- add memmove() function. Gcc may generate calls to memcmp(), memcpy(), memset() and memmove()
2021-01-25 09:27:38 +01:00
pwpiwi
efd0327132
Avoid link error due to duplicate definition of blocknr in hitag.c and hitagS.c (#963) 2021-01-25 09:26:27 +01:00
pwpiwi
622dd1af3b
Merge pull request #938 from pwpiwi/fix_printf_scanf
Fix some printf/scanf format strings
2021-01-22 17:34:42 +01:00
Iceman
e6158a48ec
Update README.md
added link to Proxmark3 community discord server
2020-07-29 17:33:56 +02:00
pwpiwi
4b27ca5cf6
Merge pull request #943 from dgorbunov/patch-1
Compile Error: Add string.h to ui.c
2020-07-14 09:00:27 +02:00
Daniel Gorbunov
79d9ddc584
Add string.h
Failed to compile without this line on MacOS Big Sur Beta.
2020-07-12 10:13:15 -04:00
pwpiwi
98a67bc908 Fix some printf/scanf format strings 2020-05-11 14:46:22 +02:00
pwpiwi
ebf1404a81
Merge pull request #926 from pwpiwi/fix_iso15693_fpga
* make fpga_version_info.c phony and delete it on 'make clean'
* wait for transfer to complete before returning from FpgaSendCommand()
* log correct tag times in iclass simulation
* shorten pulse from TC1 to TC0 in StartCountSspClk()
* shorten ssp_frame pulse in fpga/hi_reader.v
* some reformatting and whitespace fixes
* NOISE_THRESHOLD /= 2 (starting with c41dd5f it became a relative threshold)
* remove superfluous reader initialization
2020-04-11 08:56:14 +02:00
pwpiwi
c85805b8a2
update CI/.travis.yml (#929)
* drop checks for MacOS 10.11 and 10.12
* add checks for Ubuntu 16.04 and 18.04
* add libnewlib-arm-none-eabi as prerequisite on Ubuntu
2020-04-09 09:19:25 +02:00
pwpiwi
852ecedc16
compatibility fix: get_clocktime() is not always available 2020-04-07 09:04:47 +02:00
pwpiwi
6792435739 fixing iso15693
* NOISE_THRESHOLD /= 2 (starting with c41dd5f it became a relative threshold)
* remove superfluous reader initialization
2020-04-03 17:42:38 +02:00
pwpiwi
f66d28afcc Merge branch 'master' into fix_iso15693_fpga 2020-03-31 08:55:35 +02:00
pwpiwi
7a53739728 fixing some fpga and iclass issues
* make fpga_version_info.c phony and delete it on 'make clean'
* wait for transfer to complete before returning from FpgaSendCommand()
* log correct tag times in iclass simulation
* shorten pulse from TC1 to TC0 in StartCountSspClk()
* shorten ssp_frame pulse in fpga/hi_reader.v
* some reformatting and whitespace fixes
2020-03-31 08:39:16 +02:00
pwpiwi
5bc3841ad1
fix 'hf mf perso' result feedback (#920) 2020-03-16 13:33:19 +01:00
pwpiwi
aa8ff592ae
add a specific check function for static nonces (used in 'hf mf nested') (#911)
* add a specific check function for static nonces in 'hf mf nested'
* uses a fixed nr_enc and does all the crypto operations on client
* for all possible keys calculate par_enc and ar_enc and send them to device
* CHANGELOG update
2020-03-16 13:32:00 +01:00
pwpiwi
bedae7768c
Merge pull request #913 from 0x2b3bfa0/patch-1
Fix #912: ukbhit() false positive
2020-02-13 08:37:17 +01:00
Helio Machado
8f831ceb0b Fix #912 2020-02-09 18:04:46 +01:00
pwpiwi
d6e1d48284
Merge pull request #910 from pwpiwi/small_USB_response
Improve USB communications
2020-02-06 21:49:15 +01:00
pwpiwi
df7b80fecc fix WaitForResponse (without timeout) 2020-02-06 07:59:18 +01:00
pwpiwi
01aa068b6f reenable intermediate "Waiting for a response from the proxmark..." message 2020-02-04 08:21:17 +01:00
pwpiwi
3458bb279b replace msleep() by thread signalling in comms.c 2020-01-27 14:55:40 -05:00
pwpiwi
d2ca5dbfe8 uart_posix.c rework
* added some LED handling in appmain.c (helped with debugging)
* finally replaced the infamous device unlink by msleep(1000)
* fixed some format strings in comms.c (with -DCOMMS_DEBUG)
* made uart_receive() and uart_send() behave as described in header
* some formating
2020-01-27 14:14:40 -05:00
pwpiwi
fd66752193 cleaning up uart_posix.c
* whitespace fixes
* sorting out #includes
2020-01-24 03:24:39 -05:00
pwpiwi
ac37ee816b Add missing includes 2020-01-23 17:02:33 -05:00
pwpiwi
929b61c670 Always enable fast response mode (was enabled for flasher only)
* ensure that CMD_ACK is used exclusively for the very last response of each PM3 operation. All Dbprintf() must be before.
* always switch off field before exiting
* append null packet for USB transfers % 64 bytes
* reformatting and whitespace fixes
2020-01-23 22:18:51 +01:00
pwpiwi
b8ed9975e5 modify USB communications
* use different data types for commands and responses
* use variable length responses
* maintain client/flasher compatibility with old format (e.g. when using old bootloader)
* maintain bootloader compatibility with old format (e.g. when using old or RRG flasher.exe)
* fix length of version string in appmain.c
2020-01-17 09:31:14 +01:00
pwpiwi
867e10a5fd usb communication (device side) refactoring
* merge cmd.c into usb_cdc.c
* move back usb_cdc.[ch] to common/
* declare low level functions usb_read() and usb_write() and more functions as static
* use cmd_receive() in bootrom.c and appmain.c
* remove unused memory wasting csrTab[100] in usb_cdc.c
* replace more byte_t by uint8_t
* more whitespace fixes
2020-01-15 18:49:28 +01:00
pwpiwi
72622d6429 usb communication (device side) housekeeping
* move cmd.[ch] and usb_cdc.[ch] to armsrc
* sorting out #includes
* replace byte_t by uint8_t
* some reformatting
* whitespace fixes
* (no functional changes)
2020-01-15 18:46:09 +01:00
pwpiwi
d00a30d56f
Merge pull request #909 from pwpiwi/fix_button_break
Fix "Sending bytes to proxmark failed" with BUTTON_PRESS()
2020-01-15 18:31:56 +01:00
pwpiwi
6b34699adc fix "Sending bytes to proxmark failed" after BUTTON_PRESS() 2020-01-10 08:45:45 +01:00
pwpiwi
1d04b933df appmain.c cleanup
* reformatting
* whitespace fixes
* replace byte_t by uint8_t
2020-01-10 08:21:07 +01:00
pwpiwi
a749b1e58b
speedup 'hf mf chk' (#901)
* add separate timeout for tag response to nr_ar
* measure response time and use it for response timeout
* don't drop field between keyblocks
* some reformatting
* some whitespace fixes
* fishing for microseconds in TransmitFor14443a()
* allow arbitrary number of keys in MifareChkKeys()
* and move progress printing to MifareChkKeys()

Co-authored-by: uzlonewolf <github_com@hacker-nin.com>
2020-01-09 15:42:31 +01:00
pwpiwi
f0c48553cb
fix hf search (#908)
* fix memory access violation in HF14B_Other_Reader()
2020-01-07 22:33:55 +01:00
pwpiwi
fef3084ec2
fix gcc8 compiler warnings on string overflows (#905) 2020-01-03 07:17:21 +01:00
pwpiwi
a4ff62be63
fix 'hf iclass writebl' and 'hf iclass clone' (#896)
* check for correct responses after block updates
* reduce number of tries from 10 to 3
* Allow to override warning on attempt to clone blocks < 5
* add same warning and override option to 'hf iclass writebl'
* some reformatting and minor refactoring
* Drop field after dump and clone functions
* If dumping AA1 with Credit Key, authenticate as Debit Key
* Initialize reader when beginning to clone
2019-12-28 17:03:20 +01:00
Phil
1d4b67cb3d "hf mf ekeyprn d" doesn't works properly (#904)
FIX: command "hf mf ekeyprn  d" doesn't use the correct offset to locate the A key in data[] array and record the 2 last bytes followed by 4 0x00 instead of the 6 good bytes (All the A keys are corrupted in file dumpkeys.bin). B keys are not affected.
2019-12-28 14:04:46 +01:00
uzlonewolf
5a03ea993f Nested loop fix for static nonces
* add detection of static tag nonces
* add tag nonce to error message
* modify mfCheckKeys() to pass button press events upstream
* don't abort nested when a static nonce is encountered
* modify nested to try multiple keys in a single operation
* Print keys remaining only every 10 seconds, and add estimated worst-case time
2019-12-23 16:08:23 +01:00
pwpiwi
1f4789fe53
fix 'hf 15 csetuid' (#890)
* fix 'hf 15 csetuid'
* check for error codes, prevent client crash
* some include file refactoring
* some whitespace fixes
* allow longer timeout for write commands
* add function to send EOF only
* modify 'hf list 15' to display "<EOF>"
* add tracing of Reader commands
* if REQ_OPTION is set on write commands, send separate EOF to request tag response
* use #defines instead of hex constants
* switch off field after UID update
* return last tag response (if there is any)
* iso15693: decode WRITE_MULTI_BLOCK in 'hf list 15'
2019-12-20 08:25:14 +01:00
pwpiwi
e73c9f1bd4
fix 'hf iclass chk' (#894)
* Check for Credidt Keys as well
* reduce authentication tries from 6 to 3
* correct text in 'hf iclass clone' for 'l' parameter
* some reformatting and whitespace fixes
2019-12-09 08:27:42 +01:00
grauerfuchs
763d1befc1 Bugfix: Output typing on print of HID card formats (#895)
* Bugfix: Output typing on print of HID card formats

The 'PrintAndLog' calls were using signed types and sometimes too few bits in width for formatting/outputting the data as was revealed in the forums. This commit will correct the printf-formatted output typing on display of the fields.

* Update hidcardformats.c

Updated to use macros as requested by @pwpiwi
2019-12-06 16:06:24 +01:00
pwpiwi
28ae37b746
fix 'hf iclass replay' (#888)
* implement option -n for authentication with replayed NR/MAC pairs in 'dump' and 'readbl'
* delete 'hf iclass replay'
2019-12-04 18:34:53 +01:00
pwpiwi
00848e096b
Hitag fixes (#887)
* don't display error message during 'lf search' when no Hitag tag is present
* remove superfluous options in 'lf hitag read'
* fix setting of default threshold when selecting FPGA_CMD_SET_EDGE_DETECT_THRESHOLD major mode
* some refactoring
2019-11-25 08:38:23 +01:00
pwpiwi
e938f71011
Merge pull request #884 from pwpiwi/fix_iclass_snoop
* determine and write meaningful times into trace
* code deduplication: use ISO15693 snoop function
* speed up SnoopIso15693(), reduce DMA buffer size
* add jamming option '-j' to 'hf iclass snoop'
* fix issue #882
* whitespace fixes
* make room for one more bit for FPGA minor mode
* new mode FPGA_HF_READER_MODE_SEND_JAM
* implement jamming in Handle15693SampleFromReader
2019-11-19 18:11:26 +01:00
pwpiwi
cd028159be implement 'hf iclass snoop -j'
* fix long option --jam
* make room for one more bit for FPGA minor mode
* new mode FPGA_HF_READER_MODE_SEND_JAM
* implement jamming in Handle15693SampleFromReader
2019-11-13 18:03:40 +01:00
pwpiwi
be09ea8603 fix 'hf iclass snoop'
* code deduplication: use ISO15693 snoop function
* speed up SnoopIso15693(), reduce DMA buffer size
* add jamming option '-j' to 'hf iclass snoop'
* fix issue #882
* whitespace fixes
2019-11-13 18:03:39 +01:00
pwpiwi
1ce689684f fix 'hf iclass snoop'
* 'hf 15 snoop': determine and write meaningful times into trace
2019-11-13 18:03:37 +01:00
pwpiwi
d3bcdbdabf
mod 'hf list' (#881)
* switch to argtable command line parsing (i.e. options must now be preceded by '-')
* add option '-r' to display relative times
* add option '-u' to display times in microseconds
* fix: graceful exit if trace is requested from offline PM3
2019-11-13 18:00:51 +01:00
pwpiwi
496bb4be33
fix 'hf iclass' (#879)
* add loooong timeout for UPDATE command
* add flags FLAG_ICLASS_READER_INIT and FLAG_ICLASS_READER_CLEARTRACE
* don't overwrite trace buffer during 'hf iclass dump'
* fix long waiting time when start_time==0 in TransmitTo15693Tag()
* remove some additional debug prints
* refactoring: move helper functions from protocols.c to cmdhficlass.c
* add 'h' and '1' options to 'hf iclass reader' (from RRG repository)
* use correct key when only CreditKey is given in 'hf iclass dump'
* separate select_and_auth
* DropField() on errors
* dump last block in 'hf iclass dump'
* display correct memory size (number of blocks) in 'hf iclass reader' and dump
* more whitespace fixes
2019-11-13 18:00:33 +01:00
pwpiwi
ea5e5d042e
fix 'hf 14b sriwrite' (#880) 2019-11-05 11:43:03 +01:00
pwpiwi
e55b441992
Merge pull request #876 from pwpiwi/fix_iclass_reader
fix 'hf iclass reader'
* code deduplication. Use functions from iso15693.c
* speedup CodeIso15693AsReader()
* invert reader command coding. 0 now means 'unmodulated' ( = field on)
* decode SOF only as a valid tag response in Handle15693SamplesFromTag()
* complete decoding of EOF in Handle15693SamplesFromTag()
* determine and write correct times to trace
* FPGA-change: generate shorter frame signal to allow proper sync in StartCountSspClk()
* modify StartCountSspClk() for 16bit SSC transfers
* whitespace in util.c
* add specific LogTrace_ISO15693() with scaled down duration. Modify cmdhflist.c accordingly.
* allow 'hf 15 raw' with single byte commands
* check for buffer overflow, card timeout and single SOF in 'hf 15 raw'
* decode and handle SOF only responses in Handle14443bSamplesDemod()
* allow 1 byte commands with 'hf 14b raw'
* don't do READCHECK when not trying to authenticate
* standard LED handling
* remove unused FLAG_ICLASS_READER_ONLY_ONCE and FLAG_ICLASS_READER_ONE_TRY
* sanity check for negative times in TransmitTo15693Tag()
* increase reader timeout for 'hf 15' functions to be enough for slot 7 answers to ACTALL
* add 'hf iclass permute' inspired by RRG repository
* whitespace in cmdhficlass.c
2019-10-30 18:55:13 +01:00
pwpiwi
ece38ef311 fix 'hf iclass reader' and 'hf iclass readblk'
* don't do READCHECK when not trying to authenticate
* standard LED handling
* remove unused FLAG_ICLASS_READER_ONLY_ONCE and FLAG_ICLASS_READER_ONE_TRY
* sanity check for negative times in TransmitTo15693Tag()
* increase reader timeout for 'hf 15' functions to be enough for slot 7 answers to ACTALL
* add 'hf iclass permute' inspired by RRG repository
* whitespace fixes
2019-10-27 17:32:22 +01:00
pwpiwi
a3bef9863b iso14443b: trying to approach iClass
* decode and handle SOF only responses in Handle14443bSamplesDemod()
* allow 1 byte commands with 'hf 14b raw'
2019-10-23 09:09:13 +02:00
pwpiwi
a334de73d2 'hf 14b' formatting
* renaming a few functions
* whitespace
* moving a bit towards RRG repo
2019-10-22 21:02:02 +02:00
pwpiwi
c41dd5f9f6 fix 'hf iclass reader'
* code deduplication. Use functions from iso15693.c
* speedup CodeIso15693AsReader()
* invert reader command coding. 0 now means 'unmodulated' ( = field on)
* decode SOF only as a valid tag response in Handle15693SamplesFromTag()
* complete decoding of EOF in Handle15693SamplesFromTag()
* determine and write correct times to trace
* FPGA-change: generate shorter frame signal to allow proper sync in StartCountSspClk()
* modify StartCountSspClk() for 16bit SSC transfers
* whitespace in util.c
* add specific LogTrace_ISO15693() with scaled down duration. Modify cmdhflist.c accordingly.
* allow 'hf 15 raw' with single byte commands
* check for buffer overflow, card timeout and single SOF in 'hf 15 raw'
2019-10-21 21:48:08 +02:00
pwpiwi
b41be3cb11
Merge pull request #862 from pwpiwi/fix_iclass_sim
fix hf iclass sim:
* sim 2: add responses to read(1) (Config) and read(5) (AIA)
* sim 2/3: don't restrict CC to 00 bytes only
* sim 3: add responding to read block commands
* sim 2/3: add responding to READ_CHECK_KC
* fix sizes of pre-encoded tag answers
* sim 2: change default card challenge
* remove commented code
* use #defines instead of numerical constants for simulation modes
* some reformatting and whitespace fixes
* fix debug print on unhandled commands
* deduplicate: use sim functions from iso15693.c
* fix times in tracelog and 'hf list iclass' (sim only)
* don't check parity in 'hf list iclass'
* fix timing in TransmitTo15693Reader()
* add simulation of block 3 and 4 (Kd and Kc) reads
* add simulation of READ4 (4 blocks read)
* FPGA change (hi_simulate.v): avoid spp_clk phase changes
* chg to reader command decoder in iso15693.c (require no modulation before SOF)
* add 'has_been_low_for' logic to hi_simulate.v (same as in other FPGA modes, default to "no modulation")
* add simulation of chip status (IDLE, ACTIVE, SELECTED, HALTED)
* check ACSN on SELECT
* add simulation of RESELECT
* always check length of reader commands
* fix printing of NR, MAC in sim 2 mode
* fix response length to CHECK command
* implement UPDATE and CHECK[Kc]
* add simulation of multiple pages (PAGESEL by @sherhannn9)
* maintain cipher states per page
* update cipher state after UPDATE commands (@sherhannn9)
* add simulation of personalization mode
* respond with SOF on HALT
* display "\<SOF\>" instead of "0f" in 'hf list iclass'
* standard LED handling
* speedup CodeIso15693AsTag()
* TransmitTo15693Tag(): don't send unmodulated start of SOF
* reduce modulation depth in hi_simulate.v
2019-10-21 21:25:44 +02:00
Iceman
3fb6e1fa40
Merge pull request #873 from quantum-x/patch-2
Update README.md
2019-10-08 14:47:17 +02:00
quantum-x
5eacacfd9a
Update README.md
Updated as per PR discussion thead
2019-10-08 14:40:11 +02:00
quantum-x
a534629505
Update README.md
Updated reference to Lab401 as an EU reseller, not a HK reseller.
2019-10-08 13:24:25 +02:00
pwpiwi
f31b4cd888 Merge branch 'master' into fix_iclass_sim 2019-10-08 11:54:22 +02:00
pwpiwi
f784539dfb
fix iclass reader functions
* remove unused CMD_ICLASS_READCHECK
* fix wrong command coding in CodeIClassCommand()
* switch field off at end of commands to avoid RDV4 overheating
2019-10-08 11:48:49 +02:00
pwpiwi
8efd0b80f2 fix 'hf iclass sim'
* fix tag response timing. iClass differs from ISO15693 in this respect.
* speedup CodeIso15693AsTag()
* TransmitTo15693Tag(): don't send unmodulated start of SOF
* reduce modulation depth in hi_simulate.v
* calculate CRC for configuration block when simulating
* Show real response time instead of planned response time in 'hf list iclass'
2019-10-08 11:04:30 +02:00
pwpiwi
ae60ceca92 fix 'hf iclass sim'
* add simulation of multiple pages (PAGESEL by @sherhannn9)
* maintain cipher states per page
* update cipher state after UPDATE commands (@sherhannn9)
* add simulation of personalization mode
* respond with SOF on HALT
* display "<SOF>" instead of "0f" in 'hf list iclass'
* standard LED handling
2019-10-02 08:20:17 +02:00
pwpiwi
26d0156a46
fix 'hf iclass eload' (thanks to @sherhannn79) 2019-09-30 07:29:20 +01:00
pwpiwi
8ddb81a217 fix 'hf iclass sim':
* implement CHECK[Kc] based on @sherhannn79
* implement UPDATE based on @sherhannn79
2019-09-25 18:40:05 +02:00
pwpiwi
e49d31c0e7 fix 'hf iclass sim':
* ignore standard iso15693 INVENTORY commands silently
* make iso15693 command decoder more strict (prevent decoding rubbish)
* re-enable sim 3
2019-09-25 14:24:36 +02:00
pwpiwi
1963cc9fe0 Merge branch 'master' into fix_iclass_sim 2019-09-24 19:34:05 +02:00
pwpiwi
5b12974a7f fix 'hf iclass sim':
* chg to reader command decoder in iso15693.c (require no modulation before SOF)
* add 'has_been_low_for' logic to hi_simulate.v (same as in other FPGA modes, default to "no modulation")
* add simulation of chip status (IDLE, ACTIVE, SELECTED, HALTED)
* check ACSN on SELECT
* add simulation of RESELECT
* always check length of reader commands
* fix printing of NR, MAC in sim 2 mode
* fix response length to CHECK command
2019-09-24 19:23:21 +02:00
pwpiwi
70dbfc3fc7
fix compile issue with gcc 9.1.0 (issue #868) 2019-09-21 13:56:01 +01:00
pwpiwi
d8ecc98a8e
'hf iclass loclass': fix error handling (#865)
* fix handling of "BEING_CRACKED" flag
* don't try to calculate KCus when some bytes couldn't be brute forced
* whitespace fixes
2019-09-12 09:21:10 +02:00
pwpiwi
a66f26da18 fix 'hf iclass sim':
* add simulation of block 3 and 4 reads
* add simulation of READ4 (4 blocks read)
* fixing TransmitTo15693Reader()  (again)
* FPGA change (hi_simulate.v): avoid spp_clk phase changes
* some whitespace fixes
2019-09-11 07:54:56 +02:00
pwpiwi
3d2c9c9b06 fix 'hf iclass sim'
* fix debug print on unhandled commands
* deduplicate: use sim functions from iso15693.c
* fix times in tracelog and 'hf list iclass' (sim only)
* don't check parity in 'hf list iclass'
* fix timing in TransmitTo15693Reader()
2019-09-10 08:42:59 +02:00
pwpiwi
0ab9002f36 fix hf iclass sim
* sim 2: add responses to read(1) (Config) and read(5) (AIA)
* sim 2/3: don't restrict CC to 00 bytes only
* sim 3: add responding to read block commands
* sim 2/3: add responding to READ_CHECK_KC
* fix sizes of pre-encoded tag answers
* change default card challenge
* remove commented code
* use #defines instead of numerical constants for simulation modes
* some reformatting
2019-08-31 17:53:14 +02:00
pwpiwi
8b2dd94e88
Merge pull request #861 from pwpiwi/iclass_MAC_speedup
iClass MAC calculation speedup (optimized_cipher.c)
2019-08-30 17:14:26 +02:00
pwpiwi
deb965b54d add iclass.h 2019-08-25 14:03:11 +02:00
pwpiwi
a1ff338bd5 Merge branch 'master' into iclass_MAC_speedup 2019-08-24 18:27:01 +02:00
pwpiwi
1477ba8a3c iclass.c: speeding up MAC calculation 2019-08-24 18:21:01 +02:00
pwpiwi
f2dbf3d2aa
'lf hitag writer': add Hitag2 password auth
* (PRs 233, 303, 304 by @ViRb3 on https://github.com/RfidResearchGroup/proxmark3)
* replace byte_t by uint8_t
* note that Hitag1 commands are not yet available
* whitespace fixes
* #define Hitag2 commands
* whitespace
* add EOF wait time
* add powerup wait time
2019-08-22 07:54:55 +02:00
pwpiwi
0b4efbdef2
add: 'hf mf personalize' (personalize UID on Mifare Classic EV1 7byte UID cards)
* add/use some #defines
* whitespace fixes
* #include refactoring
* add line to CHANGELOG.md
2019-08-22 07:53:17 +02:00
Samuele
cfa9c98d57 PCF7931: Print found single/consecutive block(s), fixes to block 1 check 2019-08-22 07:51:46 +02:00
pwpiwi
17505ce2a7 cleaning up iclass.c and optimized_cipher.c
* add iclass.h
* reformatting
* whitespace fixes
* (no functional changes)
2019-08-22 07:44:02 +02:00
pwpiwi
f98702bace
chg 'hf mf chk':
* don't repeatedly clear trace while running (PR 243 by @mceloff from https://github.com/RfidResearchGroup/proxmark3)
* standard LED handling
* better check for key file syntax
* get rid of "res" column when printing the result. Show unknown keys more prominent as "     ?     "
2019-08-10 23:30:47 +02:00
pwpiwi
5a446cb212
'hf 14a apdu' improvement
(PR 249 by @merlokk on https://github.com/RfidResearchGroup/proxmark3)
* add option to print APDU (if it can be decoded)
* add option to cconstruct extended and normal size APDUs
2019-08-01 11:01:56 -04:00
pwpiwi
ca24170fd4
fix emv search behavior
(taken from PRs 261 and 262 by @merlokk on https://github.com/RfidResearchGroup/proxmark3)
+ whitespace fixes
2019-08-01 10:58:22 -04:00
pwpiwi
faa35ae029
fix 'hf mf sim': access conditions to write Key B were not decoded correctly
(from PR 279 https://github.com/RfidResearchGroup/proxmark3)
2019-08-01 10:55:47 -04:00
pwpiwi
3a5ffba7c1
Implement Originality Signature Check in 'hf mfu info'
* add support for elliptic curve 'secp128r1' to mbedtls library
* change ecdsa_signature_verify() to allow different curves, signature lengths, and skipping hash
* add another public key for Mifare Ultralight EV1
2019-08-01 10:53:26 -04:00
mwalker33
88b3dada70 Fix Issue #843 - hf mf chk - t Doesnt save to emulator memory 2019-07-23 20:47:29 +02:00
t0m4
096dee1784 Add 'hf 15 csetuid' command to set UID on ISO15693 Magic tags (#842) 2019-07-14 12:31:33 +02:00
marshmellow42
817611f565 update em4x05 timing (#846)
See @mwalker33 issue #838
2019-07-11 20:31:51 +02:00
marshmellow42
4d8a07c829
Merge pull request #837 from mwalker33/master
lf t55xx downlink modes support added
2019-07-11 13:17:36 -04:00
jmorsch
347efc1274 whitespace cleaning 2019-07-11 13:01:36 -04:00
mwalker33
bdc9779645 Update lfops.c
boundary length check
2019-07-07 05:00:08 +10:00
mwalker33
dcd936a1da Update lfops.c
Fixed lf t55 reset
2019-07-06 15:20:25 +10:00
mwalker33
d7569065cb Code tidy
removed commented code
2019-07-03 19:58:49 +10:00
mwalker33
28597bb6c7 Update lfops.c
moved wakeup and reset to call T55xx_SendCMD.  Small code improvements
2019-06-27 16:57:28 +10:00
mwalker33
7db36608a2 Code improved for less memory 2019-06-26 11:34:31 +10:00
pwpiwi
59f75a7895
Update CHANGELOG.md 2019-06-25 18:37:25 +02:00
mwalker33
2994ab10d6 Update CHANGELOG.md 2019-06-25 20:52:29 +10:00
mwalker33
5a9964829e Resolved Conflicts 2019-06-25 20:46:10 +10:00
mwalker33
50764caadc Update lfops.c 2019-06-25 19:28:06 +10:00
mwalker33
644493821c
Merge branch 'master' into master 2019-06-25 19:01:13 +10:00
mwalker33
e220fc63aa Update lfops.c 2019-06-25 18:56:32 +10:00
pwpiwi
d3521ae609
Update CHANGELOG.md 2019-06-24 08:42:57 +02:00
mwalker33
99c52f9d85 Update CHANGELOG.md
Change Log Update
2019-06-23 22:23:08 +10:00
marshmellow42
2de26056ce add lf em 4x05protect plus lf config s option (#833)
* add "samples to skip" for lf config (mainly for lf snoop)
* add lf em 4x05protect command to write protection on em4x05 chips
* fix spacing
* and remove old comment git added back in..
* update changelog
* fix flags - only need 1 bit
2019-06-23 13:43:55 +02:00
mwalker33
4be71814b4 T55xx Downlink - Updates
Improved code.
2019-06-22 15:26:56 +10:00
mwalker33
6763dc17a3 Cleanup Code
Update downlink option from e to r
fixed long leading reference
added downling option to original bruteforce
2019-06-18 21:17:12 +10:00
mwalker33
be1b97d81f Update cmdlft55xx.c
Fixed bruteforce filename
2019-06-17 22:01:25 +10:00
mwalker33
6dd0ff3035 Update cmdlft55xx.c
Minor Cleanup
2019-06-17 21:37:50 +10:00
mwalker33
dd8e451330 T55xx downlink Modes
Changes :
- Added t55xx downlink protocols (long leading reference, leading 0 and 1 of 4)
- Added function to all read to call differnet downlink functions (to match write)
- Update functions to support using differnet downlink modes.
- Added support for calling downlink modes for lf t55 read, write and detect
- Added new function lf t55 bruteforcedl to support downlink modes as well as try each mode
	for each password in password file.

for functions with downlink mode extenstion.

 e <mode>     - OPTIONAL downlink encoding '0' fixed-bit-length (default),
					   '1' Long Zero Reference,
					   '2' Leading Zero,
					   '3' 1 of 4
2019-06-16 15:35:10 +10:00
pwpiwi
b8dd1ef649
upgrading 'hf mfu' (#830)
* chg: write new dump file format by @mceloff
* chg: rename 'hf mfu dump' option 'n' to 'f' to align with other commands and RRG repo
* chg: replace ISO14443A_CMD_READBLOCK by MIFARE_CMD_READBLOCK, same for WRITEBLOCK
* fix: mifare_ultra_readblock() returned 14 bytes instead of 16
* chg: param_gethex_ex() now checks maximum output buffer length
* chg: ul_comp_write() was incomplete and for magic testing only
* fix: 16bit ULC counter had been displayed as 32bit
* chg: add check for 7 Byte UID, drop check for ATQA in type identification GetHF14AMfU_Type()
* fix: send HALT instead of dropping field in order to maintain a defined state
* chg: DropField() when command ends
* chg: check for invalid page ranges in 'hf mfu dump'
* fix: print correct lock bits when page range is used
* fix: do not write (incomplete) dumpfile when page range is used
* add: use UID for filename when no filename is given (RRG repo)
* chg: don't clear trace on each ULC authentication, clear trace at beginning of each command
* fix: don't send (DESFire?) deselect command after authentication
2019-06-06 07:33:12 +02:00
Vladimir Serbinenko
d38bb3acc3 Specify that we need TCP and not UDP connection (#828) 2019-05-29 18:57:17 +02:00
pwpiwi
caaa4293ad
fix 'lf pcf7931 bruteforce' (bug reported in http://www.proxmark.org/forum/viewtopic.php?id=6490) (#824)
(and whitespace fixes)
2019-05-28 07:50:58 +02:00
pwpiwi
4be9f36ebe
start updating 'hf mfu' commands (#818)
* use PrintAndLogEx()
* fix some printouts
* some #include refactoring
* whitespace
2019-05-28 07:48:55 +02:00
pwpiwi
5f18b0c45d
add: Home (Pos1) and End key bindings in graph GUI (based on @mcd1992 change on RRG repo) (#823) 2019-05-27 07:58:09 +02:00
pwpiwi
2378bb24c3
fix compiler warning in cmdhflegic.c (and whitespace fixes) (#826) 2019-05-27 07:57:40 +02:00
pwpiwi
a39af1cb9c
Add: new option 'd' in 'hf mf ekeyprn' to create dumpkeys.bin from emulator memory (#822)
(and whitespace fixes)
2019-05-22 19:02:58 +02:00
Iceman
9ebbfd898c
Update README.md 2019-04-22 18:25:52 +02:00
marshmellow42
905d2975dc
Merge pull request #817 from Fl0-0/Fix_typo_cmdlf
Fix typo lf config usage
2019-04-19 07:31:54 -04:00
Fl0-0
131c44883c
Fix typo lf config usage 2019-04-19 13:14:41 +02:00
pwpiwi
a8561e356b
fix hf mf sim (#812)
* fix parity encryption (thanks to Eloff, http://www.proxmark.org/forum/viewtopic.php?id=6347)
* add support to simulate Mifare Mini, Mifare 2K and Mifare 4K
* change to standard LED handling (A: PM is working, B: reader is sending, C: tag is responding, D: HF field is on)
* NAK on unknown commands
* allow unencrypted HALT
* don't display messages during simulation (or we will miss next reader command)
* use DMA to receive reader command
* switch earlier from send to listen mode
* move ADC initializer to iso14443_setup
* remove remainders of incomplete Mifare 10Byte UID simulation
* show 'short' bytes (7Bits or 8Bits without parity) in 'hf list mf' and 'hf list 14a'
* whitespace
2019-04-19 10:22:10 +02:00
András Veres-Szentkirályi
bad582468f Added support for Legic tags to hf search command (#815)
* hf legic: use CMD_ACK instead of Dbprintf
* hf search: add support for Legic tags
2019-04-12 08:52:18 +02:00
marshmellow42
1f61f19767
Merge pull request #808 from MalteHillmann/master
Fixed bugs for FDX-B demod
2019-03-28 19:15:44 -04:00
Malte F. Hillmann
3f306c6ded Bugfixes for LF FDX
Changed CmdBiphaseDecodeRaw to allow 7 digits
Changed CmdFdxRead to read 39999 samples instead of 10000 to improve reading from small tags
2019-03-28 22:40:29 +01:00
Malte F. Hillmann
4306de8277 fixed bug in CmdFdxDemod 2019-03-27 14:36:39 +01:00
Malte F. Hillmann
7361a18f7a fixed bug in ASKbiphaseDemod() 2019-03-27 14:34:42 +01:00
Malte F. Hillmann
9c1d59ce69 fixed bug in CmdBiphaseDecodeRaw() 2019-03-27 14:04:01 +01:00
pwpiwi
ba778bc3c4
fix FpgaSetupSsc() (#807)
* ouch! Be aware that same major modes are used in LF and HF!
2019-03-26 21:50:41 +01:00
pwpiwi
5ea2a24839
FPGA changes (#803)
* merge hf_rx_xcorr and hf_tx modes into one module with common ssp_clk and ssp_frame
* get rid of most of the warnings when compiling the HF verilog sources
* refactoring the constants in Verilog sources
2019-03-24 18:11:41 +01:00
pwpiwi
ca8a3478d9
iso14443b modifications (#804)
* LED handling
* improve 'hf plot' support
2019-03-24 18:04:42 +01:00
Oleg Moiseenko
fdd9395d1a Ndef and MAD (#801)
* move mifare stuff to separate folder
* add mad and ndef
2019-03-19 07:51:10 +01:00
Samson Gama
3d057cfb91 Added some LED utility functions (#802) 2019-03-15 07:41:07 +01:00
pwpiwi
5866c187ef
fix hitag functions (issue #798) (#800)
* ... and whitespace formating
2019-03-13 10:53:40 +01:00
pwpiwi
1523527f94
fix LED signalling in hf 15 snoop and hf 14a snoop (#797)
* LED_A (yellow): PM3 is active (snooping)
* LED_B (green): reader is sending a command
* LED_C (red): tag is sending a reply
2019-03-12 07:49:23 +01:00
pwpiwi
189b817740
add 14a apdu send framing (based on RRG repo PR86 by Merlokk) (#795) 2019-03-12 07:46:49 +01:00
pwpiwi
1338d245c2
chip manufacturer and type identification: (#796)
* add more manufacturers
* refactor chipID decoding
* move to separate file taginfo.[ch]
2019-03-03 11:59:38 +01:00
pwpiwi
b6851c194e
fix ATR length (#790)
* TS, T0, T[A-D][1-4], max. 15 HB, TCK = 34 Bytes
2019-02-26 19:48:25 +01:00
Oleg Moiseenko
0b6efd01ec Emv scan via contact interface (#789)
* share getATR from smartcard.h/c
* remove duplicates in tlv.h and add get_uint_8
* check ATS/ATR length
2019-02-21 22:02:22 +01:00
pwpiwi
fc52fbd42f
Add raw HF signal plotting (#786)
* Add raw HF signal plotting
* new fpga module hi_get_trace.v - store A/D converter output to circular buffer on FPGA
* new command 'hf plot' - pull data from FPGA and display it in Graph Window
2019-02-20 19:18:12 +01:00
Oleg Moiseenko
7527c2bdd8 fix rare bug in tlv.c (#788) 2019-02-20 18:35:39 +01:00
Fl0-0
7afa751a96 Fix for USB uart slowness since PR #720 (#787) 2019-02-17 14:43:40 +01:00
pwpiwi
53fb848a0a
add tracing functions (#784)
* add trace buffer for PCSC smartcard readers
* new option 'p' in 'hf list' to select PCSC trace buffer
* 'sc list' now supports PCSC smartcard readers
* add 'hf list 14-4' for ISO 14443-4 protocol
2019-02-16 17:51:04 +01:00
pwpiwi
3783c45af1
fix emv roca hash error (#781)
* fix ICC Public Key Hash calculation
* add -a option to 'emv roca'
* replace print() by PrintAndLogEx() in emv_pki.c
2019-02-12 09:06:30 +01:00
Oleg Moiseenko
c719d385ef fix endless loop (#782) 2019-02-09 22:38:09 +01:00
pwpiwi
41bdfce385
emv/sc fixes and modifications: (#780)
* print selected Smartcard Reader in PrintChannel()
* implement 'sc sel <readername>'. Readername can include wildcards * and ?
* fixing EMV APDU exchange (again)
* use EMVExchangeEx() instead of EMVExchange() in fidocore.c
2019-02-09 15:15:17 +01:00
pwpiwi
fbf77474f5
Update list of Certificate Authorities Public Keys (source: https://www.eftlab.co.uk/index.php/site-map/knowledge-base/243-ca-public-keys) (#777)
* allow tabs in client/emv/capk.txt
* fix issue with printing RID and CSN of certificates
2019-02-06 07:51:49 +01:00
pwpiwi
4cdd63b245
EVM fixes and additions (RRG repository PRs 78-82 by @merlokk) (#776) 2019-02-06 07:50:57 +01:00
Oleg Moiseenko
fb27c73313 added SoloKey certificate (#778) 2019-02-04 19:53:04 +01:00
Oleg Moiseenko
3962dce565 fido fix (#775) 2019-02-04 08:03:44 +01:00
pwpiwi
97096af62b
Update list of known EMV AIDs. Source: https://www.eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix (#770) 2019-02-01 21:13:00 +01:00
pwpiwi
6b5105bea9
Adding support for standard USB Smartcard Readers (#769)
* add PCSC reader support to 'sc raw' and all 'emv' commands
* move all APDU -> TPDU mapping to ExchangeAPDUSC()
* print "PSE" instead of "PPSE" when using contact interface
* fix some #defines in protocols.h
* DropField only when using contactless
* some refactoring
2019-02-01 21:12:20 +01:00
AntiCat
437035a75b Legic TagSim: increased reader timeout (#771)
Bug reports from @raphCode and @uhei over at the
RfidResearchGroup have shown that the tag to rwd
timeout is too short.
2019-01-30 22:20:57 +01:00
pwpiwi
a9104f7e31
Add support for standard USB Smartcard Readers (#765)
* add PCSC interface (pcsc.c and pcsc.h)
* new command 'sc select' to choose an USB Smartcard Reader
* updated CI/.travis.yml accordingly
* remove TCK CRC check in i2c.c It is done in PrintATR() anyway
* Fix TCK CRC check in PrintATR()
* Add PCSC reader support to 'sc info'
2019-01-28 21:54:34 +01:00
pwpiwi
1511ea28a8
Add ROCA vulnerability test (RRG repository PR 76 by @merlokk) (#762) 2019-01-21 19:26:54 +01:00
Fl0-0
d3c606574f restore #755 reverted after #757 (#761) 2019-01-17 09:13:38 +01:00
pwpiwi
151a33c027
Add smartcard protocol T=0 (RRG repository PRs 71,72,74,75 by @merlokk) (#757) 2019-01-17 07:50:01 +01:00
pwpiwi
0d2624a0cc
Add hf list 15 (#754)
and refactoring: move all of hf list code to cmdhflist.c
2019-01-16 09:54:19 +01:00
Fl0-0
c0e7527ddd Increase threshold to 160, fix for issue 756 (#760) 2019-01-16 09:52:20 +01:00
Michael Farrell
4309ef8fee Allow skipping or trying different keys in hf mf dump (#759) 2019-01-16 09:51:55 +01:00
pwpiwi
d04516a652
adjust CI testscript for new emv commands (#758) 2019-01-16 09:40:35 +01:00
Fl0-0
e59481c119 Fix CmdSmartUpgrade GCC8 strncpy specified bound depends on the length of the source argument warning (#755) 2019-01-13 16:53:09 +01:00
pwpiwi
d9de20fa4b
Fix 15 snoop (#752)
* fixing hf 15: implement hf 15 snoop
* rename hf 15 record to hf 15 snoop
* speedup sampling / decoding:
*   new FPGA mode FPGA_HF_READER_RX_XCORR_AMPLITUDE implements amplitude(ci, cq) on FPGA
*   inlining the decoders in iso15693.c
*   inlining memcpy/memset in LogTrace()
*   giving up the moving correlator for SOF in Handle15693SamplesFromTag
* decode more of EOF in Handle15693SamplesFromTag()
* some refactoring
2019-01-12 13:28:26 +01:00
pwpiwi
9f596ec7ac
RDV4.0 Smartcard Slot Firmware Upgrade (#751)
* RDV4.0 Smartcard Slot Firmware Upgrade
* new firmware in client/sc_upgrade_firmware directory
* improved sc upgrade:
   * check SHA-512 of firmware file
   * search and find firmware file in predefined directory
   * more sanity checks
* fixed offline indicators of sc commands
2019-01-12 13:26:53 +01:00
pwpiwi
6b6c3be6b9
Added ATR decoding (RfidResearchGroup PRs 67/68 by @merlokk) (#749)
... and fixed merge errors in cmdsmartcard.c
2019-01-12 13:24:22 +01:00
Fl0-0
786ad91c85 Fix CMD_PCF7931_BRUTEFORCE duplicate case value (#750) 2019-01-07 08:55:04 +01:00
Samuele
818e15b0c8 PCF7931: improved read code and implemented a simple password bruteforce (#745)
* Improved PCF 7931 read code and implemented a simple PCF7931 password bruteforce
* Warning on the PCF7931 bruteforce command
2019-01-06 18:33:06 +01:00
Fl0-0
5a28b51036 Fix PrintAndLogEx ERR (#748) 2019-01-05 18:41:51 +01:00
☃ Stephen Shkardoon ☃
5f84531b82 Paradox clone functionality implemented (#747)
This involves a refactor to the arm HID code to allow for arbitrary
preambles (such as HID Proximity and Paradox).
The client also borrows from the HID code, but is not shared, so could
use a significant refactor in the future.
2019-01-05 09:48:59 +01:00
pwpiwi
8d7d7b6187
Emv commands work with smartcard interface (RfidResearchGroup PR67 by @Merlokk) (#743)
* replace 'hf emv' commands by 'emv' commands
* Enable smartcard commands by default (-DWITH_SMARTCARD)
* update i2c.c from RfidResearchGroup repository
* update smartcard.c from RfidResearchGroup repository
2019-01-05 09:47:12 +01:00
pwpiwi
968ad67280
avoid compiler warning in client/cliparser/argtable3.c (#746) 2019-01-04 08:53:30 +01:00
Oleg Moiseenko
0d5545cee0 delete travis. it plaed in folder CI (#736) 2018-12-07 18:55:35 +01:00
Oleg Moiseenko
0bb514502a Fido2 (#727)
* add tinycbor
* add client/fido
* add test file with options for fido2
* hf fido commands
* add changelog
2018-12-07 16:42:37 +01:00
ralik
27d06e0447 Update default_pwd.dic (#735) 2018-12-07 14:10:08 +01:00
Fl0-0
daccbcdc8d Added mifare trailer block decoding for sector commands (#734) 2018-12-07 14:09:41 +01:00
pwpiwi
aa0b1c431f
Change mbedtls initializers to be compatible with older versions of gcc (#732)
* fix issue #731
2018-12-06 07:53:25 +01:00
Jean-Michel Picod
a015ef3733 Fix compilation error on OS X (#730) 2018-12-04 08:12:05 +01:00
Vladimir Serbinenko
d664113aee Support TCP ports for proxmark (#720)
On ChromeOS Linux apps can't access serial port but they can connect to TCP,
so I wrote a simple app to forward TCP to serial. I suppose this can
have other uses as well.
2018-12-03 08:53:26 +01:00
Oleg Moiseenko
ac4ecfe353 added mifare trailer block decoding (#726) 2018-12-03 08:29:13 +01:00
florianrock
383f4e2479 Update hitagS.c (#729)
Bugfix for #605 - wrong compare for tag.LKP
2018-12-03 08:23:53 +01:00
Fl0-0
9c87879e36 Fix public key lenght to 65 bytes (#725) 2018-11-30 18:44:52 +01:00
florianrock
7b6e320533 HitagS Improvements (#721)
* support of HITAG S standard communication mode
* fixed wrong AC (Anti Collision) decoding
* support of block read mode
* fixed wrong uid send when using simulation
* support of communication mode parameter  (client is backward compatible)
* support of start-page parameter (important for some weird tags) (client is backward compatible)
* also expect pages if tag memory size in con0 is 11 (we got some tags)
* corrected hitagS reader cmd help
2018-11-30 17:42:22 +01:00
Fl0-0
994f21fe01 Fix format-truncation warning, missing string.h inclusion and strnlen warning (#723)
* Fix format-truncation warning, missing string.h inclusion and strnlen warning

* Dynamic string width field
2018-11-30 09:03:44 +01:00
Oleg Moiseenko
6a2bd85719 jansson update. 2.11 to 2.12 (#724) 2018-11-30 08:43:46 +01:00
pwpiwi
5594c6215e
fix "hf mf chk" <t|d|s|ss> flags (based on PR #700) (#718) 2018-11-30 07:45:01 +01:00
Fl0-0
03439be30f Fix util.c:116:2: error: unknown type name ‘va_list’ (#722) 2018-11-26 08:11:11 +01:00
Oleg Moiseenko
6b882a3918 Fido U2F complete (#716)
* add pkwrite
* asn1print
* asn1dump and CA
* added PrintAndLogEx for merge commits between repo easier than now
* changelog
2018-11-25 16:56:12 +01:00
Oleg Moiseenko
e0991f6aa7 Get rid of polarssl (#717) 2018-11-23 19:03:46 +01:00
Oleg Moiseenko
700d868794 move from polarssl to mbedtls (#708)
* update polarssl to mbedtls
* fix a warning in armsrc/iso15693
* added random generator and ecdsa test
* added signature check to test
* move crypto lib to client directory
2018-11-19 09:02:38 +01:00
Oleg Moiseenko
39cc1c879e FIDO U2F NFC authenticators (#697)
* `hf fido` command
* detects FIDO tag
* add new commands for fido u2f
* added changelog
* added fido2 info
2018-11-17 20:22:21 +02:00
Oleg Moiseenko
8fa6838476 fix - some card cant reset so quick. (#713) 2018-11-17 19:04:56 +02:00
Oleg Moiseenko
1429030854 fix get length in tlv (#714) 2018-11-17 19:04:25 +02:00
pwpiwi
bdf96aae39 fix hf 15 reader (merge error) 2018-10-31 22:00:36 +01:00
Oleg Moiseenko
6eeb5f1c29 fix warning under linux (#709) 2018-10-31 19:47:37 +01:00
drhatson
4b5d696c17 changes to mifare plus code (#706) 2018-10-31 19:46:12 +01:00
Oleg Moiseenko
c8a0f55031 Mfp read plain (#704)
* added aes-cmac-128
* aes-cmac added to cryptosystem. not works(
2018-10-26 19:18:53 +02:00
Oleg Moiseenko
cdc9a7562d inc timeouts (#705) 2018-10-26 14:43:06 +02:00
Oleg Moiseenko
ae3340a0fb Mfp commands (#698)
* add write perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua
* commit perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L184
* added errors https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L91
* fix bug in CLIParamHexToBuf
* added init card command
* auth4 refactoring
* add changelog
2018-10-24 18:58:12 +02:00
pwpiwi
3685f89cbd small fix to please @dmaij's compiler (issue #703) 2018-10-23 19:50:37 +02:00
pwpiwi
8c6cca0ba1
Fix hf 15 sim (#696)
* added ISO15693 coding for tag messages (CodeIso15693AsTag())
* added ISO15693 decoding for reader commands (Handle15693SampleFromReader())
* send tag inventory response in either high or low speed
* some refactoring and formatting
2018-10-23 08:22:13 +02:00
Oleg Moiseenko
666fa6e1cf deploy in msys2 and proxspace (#702) 2018-10-22 22:27:37 +02:00
Oleg Moiseenko
dc3e2acf33 mf plus info with detect sl mode (#695) 2018-10-17 20:55:04 +02:00
Oleg Moiseenko
95b697f017 Emv scan (#691)
* added `hf emv scan` command and options
* add tlv tag save to json
* added tlv tree navigation
* added kernel id and moved some parts of code in ppse
* save gpo result
* added read records
* extract childs from tlv works
* added application data list
* added work with application data section
* flag --extract works
* refactoring: move json functions to emvjson.h/c
* added path.c to jansson
* refactoring: move ParamLoadFromJson
* refactoring: move defparams.json to tag-name-value structure
* refactoring and add key recovering
* added some codes to appdata list
* refactoring: process response format 1 from GPO
* added save mode
* added RID to app data
* add file name handling and small refactoring in argtable string processing
* added finalization logic to `emv scan` and option to remove hash checking in key recovery
2018-10-17 20:53:34 +02:00
Oleg Moiseenko
54e3cfcb74 small improvements in auth (#694) 2018-10-12 14:13:58 +02:00
Oleg Moiseenko
ae027818ac small fix in auth (#693) 2018-10-11 19:28:29 +02:00
Oleg Moiseenko
7dadcc959f auth 14443-4 (#692)
* AES authentication
2018-10-10 22:34:04 +02:00
349 changed files with 95619 additions and 30959 deletions

1
.gitignore vendored
View file

@ -12,6 +12,7 @@
*.map
*.bin
!client/hardnested/*.bin
!client/sc_upgrade_firmware/*.bin
*.dll
*.moc.cpp
*.z

View file

@ -5,10 +5,47 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased]
### Changed
- Changed hf mfp security. Now it works in all the modes. (drHatson)
- `hf fido` - show/check DER certificate and signatures (Merlok)
- Changed `lf hitag reader 0x ... <firstPage> <tagmode>` - to select first page to read and tagmode (0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED)
- Accept hitagS con0 tags with memory bits set to 11 and handle like 2048 tag
### Fixed
- AC-Mode decoding for HitagS
- Wrong UID at HitagS simulation
- `hf 15 sim` now works as expected (piwi)
- `hf mf chk t` save to emulator memory now works as expected (mwalker)
- Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff)
- allow files > 512Bytes in 'hf iclass eload' (@Sherhannn79)
- `hf mf nested` now works with fixed nonce tags too (uzlonewolf, piwi)
### Added
- Added to `hf 14a apdu` print apdu and compose apdu (@merlokk)
- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4)
- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow)
- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow)
- Support Standard Communication Mode in HITAG S
- Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok)
- `hf mfp` group of commands (Merlok)
- Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok)
- Added `lf hitag reader 03` - read block (instead of pages)
- Added `lf hitag reader 04` - read block (instead of pages)
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok)
- Added `lf paradox clone` to clone a Paradox card
- Added `emv` commands working for both contactless and smart cards (Merlok)
- Added `hf 15 snoop` (piwi)
- Added support for standard USB Smartcard Readers (piwi)
- Added `hf plot` (piwi)
- Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok)
- Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok)
- Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi)
- Added Legic detection to `hf search` (dnet)
- Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992)
- Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce`
- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password
- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi)
- Added `hf mf personalize` to personalize the UID option of Mifare Classic EV1 cards (piwi)
## [v3.1.0][2018-10-10]

View file

@ -1,23 +1,28 @@
# Travis-CI config
# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3"
language: c
compiler: gcc
# Test on Linux and MacOS
matrix:
jobs:
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.4 # OS X 10.13
- os: osx
osx_image: xcode10 # OS X 10.13
- os: osx
osx_image: xcode11 # OS X 10.14
- os: linux
dist: trusty
sudo: required
dist: trusty # Ubuntu 14.04
- os: linux
dist: xenial # Ubuntu 16.04
- os: linux
dist: bionic # Ubuntu 18.04
git:
depth: false
before_install:
## Install ARM toolchain on Linux.
@ -26,13 +31,13 @@ before_install:
echo $REPOSITORY_EP;
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get update -qq;
sudo apt-get install -y gcc-arm-none-eabi;
sudo apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi libpcsclite-dev;
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update;
if [[ "$REPOSITORY_EP" == "" ]]; then
brew tap proxmark/proxmark3;
brew tap --full proxmark/proxmark3;
else
brew tap "$REPOSITORY_EP" --env=std;
brew tap --full "$REPOSITORY_EP" --env=std;
fi
fi
@ -47,7 +52,7 @@ install:
before_script:
script:
## for the time being we are satisfied if it can be build and then successfully started
## for the time being we are satisfied if it can be build and hf mf hardnested runs
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
proxmark3 /dev/notexists travis_test_commands.scr ;
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then

View file

@ -66,9 +66,20 @@ clone_script:
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Fill msys\etc\fstab file..." -NoNewLine
Write-Host "Fill msys2\etc\fstab file..." -NoNewLine
New-Item c:\ProxSpace\msys\etc\fstab -type file -force -value "#Win32_Path Mount_Point`nc:\ProxSpace\devkitARM /devkitARM`nc:\ProxSpace\Qt\5.6 /qt `nc:\ProxSpace\pm3 /pm3`n"
New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n"
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Update msys2 packages..." -NoNewLine
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
Write-Host "[ OK ]" -ForegroundColor Green
install:
@ -84,12 +95,25 @@ install:
}
build_script:
- ps: >-
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
"C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
$env:MINGW_HOME="C:\ProxSpace\msys2\mingw32"
$env:MSYS_HOME="C:\ProxSpace\msys2"
$env:MSYSTEM="MINGW32"
$env:MINGW_PREFIX="/mingw32"
$env:SHELL="/bin/bash"
$env:MSYSTEM_CHOST="i686-w64-mingw32"
#make
bash -lc -i "pwd;make all"
bash -c -i 'pwd;make clean;make all'
#some checks
@ -233,14 +257,14 @@ test_script:
[bool]$res=$false
# Wait 120 sec timeout for Job
if(Wait-Job $Job -Timeout 120){
if(Wait-Job $Job -Timeout 150){
$Results = $Job | Receive-Job
if($Results -like "true"){
$res=$true
}
} else {
Write-host "Test [$Name] timeout" -ForegroundColor Red
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 40000 -ErrorMessage "timeout"
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 60000 -ErrorMessage "timeout"
}
Remove-Job -Force $Job
@ -268,19 +292,19 @@ test_script:
#proxmark logic tests
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q Execute && echo Passed || echo Failed'}
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q 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 "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 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:"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:"
#proxmark crypto tests
ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;proxmark3 comx -c 'hf emv test'"} "Tests ?OK"
ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf emv test'"} "Tests ?OK"
if ($global:TestsPassed) {

View file

@ -1,3 +1,3 @@
hf mf hardnested t 1 000000000000
hf emv test
emv test
exit

View file

@ -16,6 +16,7 @@ do something useful with a proxmark3.
* [The Forum](http://www.proxmark.org/forum)
* The IRC channel: irc.freenode.org #proxmark3 ([chat in your browser](http://webchat.freenode.net/?channels=#proxmark3))
* [The Homebrew formula repository](https://github.com/Proxmark/homebrew-proxmark3)
* [Proxmark3 community discord server](https://discord.gg/86VcRtS)
## Development
@ -27,12 +28,15 @@ your operating system. Please refer to [the wiki](https://github.com/Proxmark/pr
The Proxmark3 is available for purchase (assembled and tested) from the
following locations:
* [RyscCorp](https://proxmark3.com/) (US)
* [Hackerwarehouse](https://hackerwarehouse.com/) (US)
* [Elechouse](http://www.elechouse.com/) (HK)
* [Lab401](https://lab401.com/) (FR)
* [RFxSecure](http://www.rfxsecure.com/) (SG)
* [IceSQL](http://proxmark3.tictail.com/) (SE)
| Distributor Name | Warehouse Location | Entity Location |
|------------------|--------------------|-----------------|
| [RyscCorp](https://proxmark3.com/) | USA | USA |
| [Hackerwarehouse](https://hackerwarehouse.com/) | USA | USA |
| [Elechouse](http://www.elechouse.com/) | HK | HK |
| [Lab401](https://lab401.com/) | EU | HK |
| [RFxSecure](http://www.rfxsecure.com/) | CN | SG |
| [Sneaktechnology](https://www.sneaktechnology.com/) | CN | CN |
Most of the ultra-low-volume contract assemblers could put
something like this together with a reasonable yield. A run of around

View file

@ -36,8 +36,9 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE;
static uint8_t *emulator_memory = NULL;
// trace related variables
static uint16_t traceLen = 0;
int tracing = 1; //Last global one.. todo static?
static uint32_t traceLen = 0;
static bool tracing = true;
// get the address of BigBuf
uint8_t *BigBuf_get_addr(void)
@ -63,6 +64,8 @@ void BigBuf_Clear(void)
{
BigBuf_Clear_ext(true);
}
// clear ALL of BigBuf
void BigBuf_Clear_ext(bool verbose)
{
@ -70,10 +73,13 @@ void BigBuf_Clear_ext(bool verbose)
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);
@ -128,18 +134,22 @@ uint16_t BigBuf_max_traceLen(void)
return BigBuf_hi;
}
void clear_trace() {
traceLen = 0;
}
void set_tracing(bool enable) {
tracing = enable;
}
bool get_tracing(void) {
return tracing;
}
/**
* Get the number of bytes traced
* @return
@ -149,6 +159,7 @@ 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
@ -162,8 +173,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
uint8_t *trace = BigBuf_get_addr();
uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
uint16_t duration = timestamp_end - timestamp_start;
uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
uint32_t duration = timestamp_end - timestamp_start;
// Return when trace is full
uint16_t max_traceLen = BigBuf_max_traceLen();
@ -200,19 +211,23 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
// data bytes
if (btBytes != NULL && iLen != 0) {
memcpy(trace + traceLen, btBytes, iLen);
for (int i = 0; i < iLen; i++) {
trace[traceLen++] = *btBytes++;
}
}
traceLen += iLen;
// parity bytes
if (num_paritybytes != 0) {
if (parity != NULL) {
memcpy(trace + traceLen, parity, num_paritybytes);
for (int i = 0; i < num_paritybytes; i++) {
trace[traceLen++] = *parity++;
}
} else {
memset(trace + traceLen, 0x00, num_paritybytes);
for (int i = 0; i < num_paritybytes; i++) {
trace[traceLen++] = 0x00;
}
}
}
traceLen += num_paritybytes;
return true;
}
@ -229,8 +244,11 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
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;
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)
@ -238,6 +256,8 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
// 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);
@ -254,8 +274,9 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
trace[traceLen++] = ((dwParity >> 24) & 0xff);
trace[traceLen++] = iBits;
memcpy(trace + traceLen, btBytes, iLen);
traceLen += iLen;
for (int i = 0; i < iLen; i++) {
trace[traceLen++] = *btBytes++;
}
return true;
}

View file

@ -21,11 +21,12 @@ else
SRC_LCD =
endif
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO15693 = iso15693.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c
SRC_ISO14443b = iso14443b.c
SRC_CRAPTO1 = crypto1.c des.c
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c
SRC_CRAPTO1 = crypto1.c
SRC_DES = platform_util_arm.c des.c
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c iso15693tools.c
SRC_SMARTCARD = i2c.c
#the FPGA bitstream files. Note: order matters!
@ -42,7 +43,6 @@ APP_CFLAGS += -I../zlib
# Compile these in thumb mode (small size)
THUMBSRC = start.c \
$(SRC_LCD) \
$(SRC_ISO15693) \
$(SRC_LF) \
$(SRC_ZLIB) \
$(SRC_SMARTCARD) \
@ -50,8 +50,10 @@ THUMBSRC = start.c \
printf.c \
util.c \
string.c \
usb_cdc.c \
cmd.c
usb_cdc.c
# Compile these in thumb mode optimized for speed (still smaller than ARM mode)
THUMBOPTSRC = $(SRC_ISO15693)
# These are to be compiled in ARM mode
ARMSRC = fpgaloader.c \
@ -61,6 +63,7 @@ ARMSRC = fpgaloader.c \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
$(SRC_DES) \
$(SRC_CRC) \
iclass.c \
BigBuf.c \
@ -70,7 +73,7 @@ ARMSRC = fpgaloader.c \
VERSIONSRC = version.c \
fpga_version_info.c
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
# Do not move this inclusion before the definition of {THUMB,THUMBOPT,ASM,ARM}SRC
include ../common/Makefile.common
OBJS = $(OBJDIR)/fullimage.s19
@ -80,8 +83,9 @@ all: $(OBJS)
.DELETE_ON_ERROR:
# version.c should be remade on every compilation
.PHONY: version.c
# version.c and fpga_version_info.c to be remade on every compilation
.PHONY: version.c fpga_version_info.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
@ -97,7 +101,7 @@ $(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR):
make -C ../client $(notdir $(FPGA_COMPRESSOR))
$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(THUMBOPTOBJ) $(ARMOBJ)
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf
@ -129,7 +133,7 @@ clean:
$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(DELETE) $(OBJDIR)$(PATHSEP)*.z
$(DELETE) $(OBJDIR)$(PATHSEP)*.bin
$(DELETE) version.c
$(DELETE) version.c fpga_version_info.c
.PHONY: all clean help
help:

View file

@ -13,7 +13,6 @@
#include <stdarg.h>
#include "usb_cdc.h"
#include "cmd.h"
#include "proxmark3.h"
#include "apps.h"
#include "fpga.h"
@ -24,15 +23,23 @@
#include "legicrfsim.h"
#include "hitag2.h"
#include "hitagS.h"
#include "iclass.h"
#include "iso14443b.h"
#include "iso15693.h"
#include "lfsampling.h"
#include "BigBuf.h"
#include "mifarecmd.h"
#include "mifareutil.h"
#include "mifaresim.h"
#include "pcf7931.h"
#include "i2c.h"
#include "hfsnoop.h"
#include "fpgaloader.h"
#ifdef WITH_LCD
#include "LCD.h"
#endif
static uint32_t hw_capabilities;
// Craig Young - 14a stand-alone code
#ifdef WITH_ISO14443a
@ -51,14 +58,12 @@ int ToSendMax;
static int ToSendBit;
struct common_area common_area __attribute__((section(".commonarea")));
void ToSendReset(void)
{
void ToSendReset(void) {
ToSendMax = -1;
ToSendBit = 8;
}
void ToSendStuffBit(int b)
{
void ToSendStuffBit(int b) {
if (ToSendBit >= 8) {
ToSendMax++;
ToSend[ToSendMax] = 0;
@ -81,19 +86,11 @@ void ToSendStuffBit(int b)
// Debug print functions, to go out over USB, to the usual PC-side client.
//=============================================================================
void DbpString(char *str)
{
byte_t len = strlen(str);
cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len);
void DbpString(char *str) {
uint8_t len = strlen(str);
cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(uint8_t*)str,len);
}
#if 0
void DbpIntegers(int x1, int x2, int x3)
{
cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0);
}
#endif
void Dbprintf(const char *fmt, ...) {
// should probably limit size here; oh well, let's just use a big buffer
char output_string[128];
@ -138,8 +135,7 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) {
// in ADC units (0 to 1023). Also a routine to average 32 samples and
// return that.
//-----------------------------------------------------------------------------
static int ReadAdc(int ch)
{
static int ReadAdc(int ch) {
// Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value.
// AMPL_HI is a high impedance (10MOhm || 1MOhm) output, the input capacitance of the ADC is 12pF (typical). This results in a time constant
// of RC = (0.91MOhm) * 12pF = 10.9us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged.
@ -163,8 +159,7 @@ static int ReadAdc(int ch)
return AT91C_BASE_ADC->ADC_CDR[ch] & 0x3ff;
}
int AvgAdc(int ch) // was static - merlok
{
int AvgAdc(int ch) { // was static - merlok{
int i;
int a = 0;
@ -175,8 +170,7 @@ int AvgAdc(int ch) // was static - merlok
return (a + 15) >> 5;
}
static int AvgAdc_Voltage_HF(void)
{
static int AvgAdc_Voltage_HF(void) {
int AvgAdc_Voltage_Low, AvgAdc_Voltage_High;
AvgAdc_Voltage_Low= (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10;
@ -190,13 +184,11 @@ static int AvgAdc_Voltage_HF(void)
return AvgAdc_Voltage_Low;
}
static int AvgAdc_Voltage_LF(void)
{
static int AvgAdc_Voltage_LF(void) {
return (MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10;
}
void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[])
{
void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[]) {
int i, adcval = 0, peak = 0;
/*
@ -234,20 +226,18 @@ void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv
return;
}
void MeasureAntennaTuningHfOnly(int *vHf)
{
void MeasureAntennaTuningHfOnly(int *vHf) {
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
LED_A_ON();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
SpinDelay(20);
*vHf = AvgAdc_Voltage_HF();
LED_A_OFF();
return;
}
void MeasureAntennaTuning(int mode)
{
void MeasureAntennaTuning(int mode) {
uint8_t LF_Results[256] = {0};
int peakv = 0, peakf = 0;
int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
@ -273,15 +263,14 @@ void MeasureAntennaTuning(int mode)
return;
}
void MeasureAntennaTuningHf(void)
{
void MeasureAntennaTuningHf(void) {
int vHf = 0; // in mV
DbpString("Measuring HF antenna, press button to exit");
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
for (;;) {
SpinDelay(500);
@ -297,8 +286,7 @@ void MeasureAntennaTuningHf(void)
}
void ReadMem(int addr)
{
void ReadMem(int addr) {
const uint8_t *data = ((uint8_t *)addr);
Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",
@ -311,8 +299,21 @@ extern struct version_information version_information;
extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__;
void SendVersion(void)
{
void set_hw_capabilities(void) {
if (I2C_is_available()) {
hw_capabilities |= HAS_SMARTCARD_SLOT;
}
if (false) { // TODO: implement a test
hw_capabilities |= HAS_EXTRA_FLASH_MEM;
}
}
void SendVersion(void) {
LED_A_ON();
set_hw_capabilities();
char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */
char VersionString[USB_CMD_DATA_SIZE] = { '\0' };
@ -346,13 +347,13 @@ void SendVersion(void)
// Send Chip ID and used flash memory
uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start;
uint32_t compressed_data_section_size = common_area.arg1;
cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString));
cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString) + 1);
LED_A_OFF();
}
// measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the UsbCommand structure included.
void printUSBSpeed(void)
{
void printUSBSpeed(void) {
Dbprintf("USB Speed:");
Dbprintf(" Sending USB packets to client...");
@ -363,13 +364,11 @@ void printUSBSpeed(void)
uint32_t start_time = end_time = GetTickCount();
uint32_t bytes_transferred = 0;
LED_B_ON();
while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) {
cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE);
end_time = GetTickCount();
bytes_transferred += USB_CMD_DATA_SIZE;
}
LED_B_OFF();
Dbprintf(" Time elapsed: %dms", end_time - start_time);
Dbprintf(" Bytes transferred: %d", bytes_transferred);
@ -381,8 +380,8 @@ void printUSBSpeed(void)
/**
* Prints runtime information about the PM3.
**/
void SendStatus(void)
{
void SendStatus(void) {
LED_A_ON();
BigBuf_print_status();
Fpga_print_status();
#ifdef WITH_SMARTCARD
@ -396,14 +395,14 @@ void SendStatus(void)
Dbprintf(" ToSendBit..........%d", ToSendBit);
cmd_send(CMD_ACK, 1, 0, 0, 0, 0);
LED_A_OFF();
}
#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone)
#define OPTS 2
void StandAloneMode()
{
void StandAloneMode() {
DbpString("Stand-alone mode! No PC necessary.");
// Oooh pretty -- notify user we're in elite samy mode now
LED(LED_RED, 200);
@ -415,7 +414,6 @@ void StandAloneMode()
LED(LED_GREEN, 200);
LED(LED_ORANGE, 200);
LED(LED_RED, 200);
}
#endif
@ -423,8 +421,7 @@ void StandAloneMode()
#ifdef WITH_ISO14443a_StandAlone
void StandAloneMode14a()
{
void StandAloneMode14a() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
@ -440,14 +437,12 @@ void StandAloneMode14a()
LED(selected + 1, 0);
for (;;)
{
for (;;) {
usb_poll();
WDT_HIT();
SpinDelay(300);
if (GotoRecord || !cardRead[selected])
{
if (GotoRecord || !cardRead[selected]) {
GotoRecord = false;
LEDsoff();
LED(selected + 1, 0);
@ -462,28 +457,24 @@ void StandAloneMode14a()
uint32_t cuid;
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
for ( ; ; )
{
for ( ; ; ) {
WDT_HIT();
if (BUTTON_PRESS()) {
if (cardRead[selected]) {
Dbprintf("Button press detected -- replaying card in bank[%d]", selected);
break;
}
else if (cardRead[(selected+1)%OPTS]) {
} else if (cardRead[(selected+1)%OPTS]) {
Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS);
selected = (selected+1)%OPTS;
break;
}
else {
} else {
Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
SpinDelay(300);
}
}
if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0, true))
continue;
else
{
else {
Dbprintf("Read UID:"); Dbhexdump(10,uid,0);
memcpy(readUID,uid,10*sizeof(uint8_t));
uint8_t *dst = (uint8_t *)&uid_tmp1;
@ -495,14 +486,12 @@ void StandAloneMode14a()
dst[i] = uid[7-i];
if (uid_1st[(selected+1) % OPTS] == uid_tmp1 && uid_2nd[(selected+1) % OPTS] == uid_tmp2) {
Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping.");
}
else {
} else {
if (uid_tmp2) {
Dbprintf("Bank[%d] received a 7-byte UID", selected);
uid_1st[selected] = (uid_tmp1)>>8;
uid_2nd[selected] = (uid_tmp1<<24) + (uid_tmp2>>8);
}
else {
} else {
Dbprintf("Bank[%d] received a 4-byte UID", selected);
uid_1st[selected] = uid_tmp1;
uid_2nd[selected] = uid_tmp2;
@ -526,10 +515,7 @@ void StandAloneMode14a()
playing = true;
cardRead[selected] = true;
}
/* MF Classic UID clone */
else if (GotoClone)
{
} else if (GotoClone) { /* MF Classic UID clone */
GotoClone=false;
LEDsoff();
LED(selected + 1, 0);
@ -540,8 +526,7 @@ void StandAloneMode14a()
Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]);
// wait for button to be released
while(BUTTON_PRESS())
{
while(BUTTON_PRESS()) {
// Delay cloning until card is in place
WDT_HIT();
}
@ -582,8 +567,7 @@ void StandAloneMode14a()
if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
playing = true;
}
else {
} else {
Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]);
memcpy(newBlock0, oldBlock0, 16);
// Copy uid_1st for bank (2nd is for longer UIDs not supported if classic)
@ -596,15 +580,13 @@ void StandAloneMode14a()
// arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain
MifareCSetBlock(0, 0xFF, 0, newBlock0);
MifareCGetBlock(0x3F, 1, 0, testBlock0);
if (memcmp(testBlock0,newBlock0,16)==0)
{
if (memcmp(testBlock0, newBlock0, 16) == 0) {
DbpString("Cloned successfull!");
cardRead[selected] = false; // Only if the card was cloned successfully should we clear it
playing = false;
GotoRecord = true;
selected = (selected+1) % OPTS;
}
else {
} else {
Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
playing = true;
}
@ -612,10 +594,9 @@ void StandAloneMode14a()
LEDsoff();
LED(selected + 1, 0);
}
} else if (playing) {
// button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
// Change where to record (or begin playing)
else if (playing) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
{
LEDsoff();
LED(selected + 1, 0);
@ -631,27 +612,22 @@ void StandAloneMode14a()
if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) {
DbpString("Mifare Classic");
SimulateIso14443aTag(1, uid_1st[selected], uid_2nd[selected], data); // Mifare Classic
}
else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) {
} else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) {
DbpString("Mifare Ultralight");
SimulateIso14443aTag(2, uid_1st[selected], uid_2nd[selected], data); // Mifare Ultralight
}
else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) {
} else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) {
DbpString("Mifare DESFire");
SimulateIso14443aTag(3, uid_1st[selected], uid_2nd[selected], data); // Mifare DESFire
}
else {
} else {
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
SimulateIso14443aTag(1, uid_1st[selected], uid_2nd[selected], data);
}
}
else if (button_action == BUTTON_SINGLE_CLICK) {
} else if (button_action == BUTTON_SINGLE_CLICK) {
selected = (selected + 1) % OPTS;
Dbprintf("Done playing. Switching to record mode on bank %d",selected);
GotoRecord = true;
break;
}
else if (button_action == BUTTON_HOLD) {
} else if (button_action == BUTTON_HOLD) {
Dbprintf("Playtime over. Begin cloning...");
GotoClone = true;
break;
@ -666,10 +642,11 @@ void StandAloneMode14a()
}
}
}
#elif WITH_LF_StandAlone
// samy's sniff and repeat routine
void SamyRun()
{
void SamyRun() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
@ -681,8 +658,7 @@ void SamyRun()
// Turn on selected LED
LED(selected + 1, 0);
for (;;)
{
for (;;) {
usb_poll();
WDT_HIT();
@ -691,8 +667,7 @@ void SamyRun()
SpinDelay(300);
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0)
{
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
@ -723,10 +698,7 @@ void SamyRun()
cardRead = 1;
}
else if (button_pressed > 0 && cardRead == 1)
{
} else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 0);
@ -744,7 +716,7 @@ void SamyRun()
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)));
CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)), 0x1D);
if (tops[selected] > 0)
Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
else
@ -760,11 +732,9 @@ void SamyRun()
cardRead = 0;
}
} else if (button_pressed) {
// Change where to record (or begin playing)
else if (button_pressed)
{
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
@ -774,8 +744,7 @@ void SamyRun()
LED(selected + 1, 0);
// Begin transmitting
if (playing)
{
if (playing) {
LED(LED_GREEN, 0);
DbpString("Playing");
// wait for button to be released
@ -788,8 +757,7 @@ void SamyRun()
CmdHIDsimTAG(tops[selected], high[selected], low[selected], 0);
DbpString("Done playing");
if (BUTTON_HELD(1000) > 0)
{
if (BUTTON_HELD(1000) > 0) {
DbpString("Exiting");
LEDsoff();
return;
@ -803,8 +771,7 @@ void SamyRun()
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
}
else
} else
while(BUTTON_PRESS())
WDT_HIT();
}
@ -812,6 +779,7 @@ void SamyRun()
}
#endif
/*
OBJECTIVE
Listen and detect an external reader. Determine the best location
@ -847,10 +815,10 @@ static const char LIGHT_SCHEME[] = {
0xE, /* -XXX | 86% of maximum current detected */
0xF, /* XXXX | 100% of maximum current detected */
};
static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
void ListenReaderField(int limit)
{
void ListenReaderField(int limit) {
int lf_av, lf_av_new=0, lf_baseline= 0, lf_max;
int hf_av, hf_av_new=0, hf_baseline= 0, hf_max;
int mode=1, display_val, display_max, i;
@ -897,7 +865,8 @@ void ListenReaderField(int limit)
return;
break;
}
while (BUTTON_PRESS());
while (BUTTON_PRESS())
/* wait */;
}
WDT_HIT();
@ -955,7 +924,7 @@ void ListenReaderField(int limit)
}
}
for (i = 0; i < LIGHT_LEN; i++) {
if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
if (display_val >= (display_max / LIGHT_LEN * i) && display_val <= (display_max / LIGHT_LEN * (i+1))) {
if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
@ -967,16 +936,15 @@ void ListenReaderField(int limit)
}
}
void UsbPacketReceived(uint8_t *packet, int len)
{
UsbCommand *c = (UsbCommand *)packet;
void UsbPacketReceived(UsbCommand *c) {
// Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]);
switch(c->cmd) {
#ifdef WITH_LF
case CMD_SET_LF_SAMPLING_CONFIG:
setSamplingConfig((sample_config *) c->d.asBytes);
setSamplingConfig(c->d.asBytes);
break;
case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
cmd_send(CMD_ACK,SampleLF(c->arg[0], c->arg[1]),0,0,0,0);
@ -1003,7 +971,11 @@ void UsbPacketReceived(uint8_t *packet, int len)
CmdPSKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_HID_CLONE_TAG:
CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x1D);
break;
case CMD_PARADOX_CLONE_TAG:
// Paradox cards are the same as HID, with a different preamble, so we can reuse the same function
CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x0F);
break;
case CMD_IO_DEMOD_FSK:
CmdIOdemodFSK(c->arg[0], 0, 0, 1);
@ -1055,12 +1027,18 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_PCF7931_WRITE:
WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_PCF7931_BRUTEFORCE:
BruteForcePCF7931(c->arg[0], (c->arg[1] & 0xFF), c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128);
break;
case CMD_EM4X_READ_WORD:
EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]);
break;
case CMD_EM4X_WRITE_WORD:
EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_EM4X_PROTECT:
EM4xProtect(c->arg[0], c->arg[1], c->arg[2]);
break;
case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
break;
@ -1077,19 +1055,22 @@ void UsbPacketReceived(uint8_t *packet, int len)
SnoopHitag(c->arg[0]);
break;
case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content
SimulateHitagTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
SimulateHitagTag((bool)c->arg[0], (uint8_t*)c->d.asBytes);
break;
case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function
ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
break;
case CMD_SIMULATE_HITAG_S:// Simulate Hitag s tag, args = memory content
SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
SimulateHitagSTag((bool)c->arg[0],(uint8_t*)c->d.asBytes);
break;
case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file
check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes);
check_challenges_cmd((bool)c->arg[0], (uint8_t*)c->d.asBytes, (uint8_t)c->arg[1]);
break;
case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge
ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], false);
break;
case CMD_READ_HITAG_S_BLK:
ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], true);
break;
case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge
if ((hitag_function)c->arg[0] < 10) {
@ -1105,8 +1086,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
AcquireRawAdcSamplesIso15693();
break;
case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693:
RecordRawAdcSamplesIso15693();
case CMD_SNOOP_ISO_15693:
SnoopIso15693(0, NULL);
break;
case CMD_ISO_15693_COMMAND:
@ -1124,9 +1106,14 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_READER_ISO_15693:
ReaderIso15693(c->arg[0]);
break;
case CMD_SIMTAG_ISO_15693:
SimTagIso15693(c->arg[0], c->d.asBytes);
break;
case CMD_CSETUID_ISO_15693:
SetTag15693Uid(c->d.asBytes);
break;
#endif
#ifdef WITH_LEGICRF
@ -1203,6 +1190,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MIFARE_WRITEBL:
MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_PERSONALIZE_UID:
MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes);
break;
//case CMD_MIFAREU_WRITEBL_COMPAT:
//MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
//break;
@ -1219,7 +1209,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_SIMULATE_MIFARE_CARD:
Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
MifareSim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
// emulator
@ -1263,7 +1253,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
#ifdef WITH_ICLASS
// Makes use of ISO14443a FPGA Firmware
case CMD_SNOOP_ICLASS:
SnoopIClass();
SnoopIClass(c->arg[0], c->d.asBytes);
break;
case CMD_SIMULATE_TAG_ICLASS:
SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
@ -1271,23 +1261,20 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_READER_ICLASS:
ReaderIClass(c->arg[0]);
break;
case CMD_READER_ICLASS_REPLAY:
ReaderIClass_Replay(c->arg[0], c->d.asBytes);
break;
case CMD_ICLASS_EML_MEMSET:
emlSet(c->d.asBytes,c->arg[0], c->arg[1]);
break;
case CMD_ICLASS_WRITEBLOCK:
iClass_WriteBlock(c->arg[0], c->d.asBytes);
break;
case CMD_ICLASS_READCHECK: // auth step 1
iClass_ReadCheck(c->arg[0], c->arg[1]);
break;
case CMD_ICLASS_READBLOCK:
iClass_ReadBlk(c->arg[0]);
break;
case CMD_ICLASS_AUTHENTICATION: //check
iClass_Authentication(c->d.asBytes);
case CMD_ICLASS_CHECK:
iClass_Check(c->d.asBytes);
break;
case CMD_ICLASS_READCHECK:
iClass_Readcheck(c->arg[0], c->arg[1]);
break;
case CMD_ICLASS_DUMP:
iClass_Dump(c->arg[0], c->arg[1]);
@ -1296,11 +1283,16 @@ void UsbPacketReceived(uint8_t *packet, int len)
iClass_Clone(c->arg[0], c->arg[1], c->d.asBytes);
break;
#endif
#ifdef WITH_HFSNOOP
case CMD_HF_SNIFFER:
HfSnoop(c->arg[0], c->arg[1]);
break;
case CMD_HF_PLOT:
HfPlot();
break;
#endif
#ifdef WITH_SMARTCARD
case CMD_SMART_ATR: {
SmartCardAtr();
@ -1344,13 +1336,14 @@ void UsbPacketReceived(uint8_t *packet, int len)
break;
case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
LED_A_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
LED_D_OFF(); // LED D indicates field ON or OFF
LED_A_OFF();
break;
case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K:
LED_B_ON();
uint8_t *BigBuf = BigBuf_get_addr();
for(size_t i=0; i<c->arg[1]; i += USB_CMD_DATA_SIZE) {
@ -1436,7 +1429,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_DEVICE_INFO: {
uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0);
cmd_send_old(CMD_DEVICE_INFO,dev_info,0,0,0,0);
break;
}
default:
@ -1445,8 +1438,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
}
}
void __attribute__((noreturn)) AppMain(void)
{
void __attribute__((noreturn)) AppMain(void) {
SpinDelay(100);
clear_trace();
if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
@ -1457,10 +1451,7 @@ void __attribute__((noreturn)) AppMain(void)
}
common_area.flags.osimage_present = 1;
LED_D_OFF();
LED_C_OFF();
LED_B_OFF();
LED_A_OFF();
LEDsoff();
// Init USB device
usb_enable();
@ -1476,11 +1467,11 @@ void __attribute__((noreturn)) AppMain(void)
// Reset SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // required twice on some AT91SAM Revisions (see Errata in AT91SAM datasheet)
// Reset SSC
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// Load the FPGA image, which we have stored in our flash.
// (the HF version by default)
// Load the FPGA image, which we have stored in our flash (HF version by default)
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
StartTickCount();
@ -1489,29 +1480,21 @@ void __attribute__((noreturn)) AppMain(void)
LCDInit();
#endif
byte_t rx[sizeof(UsbCommand)];
size_t rx_len;
UsbCommand rx;
for(;;) {
if (usb_poll()) {
rx_len = usb_read(rx,sizeof(UsbCommand));
if (rx_len) {
UsbPacketReceived(rx,rx_len);
}
}
WDT_HIT();
#ifdef WITH_LF_StandAlone
#ifndef WITH_ISO14443a_StandAlone
if (cmd_receive(&rx)) {
UsbPacketReceived(&rx);
} else {
#if defined(WITH_LF_StandAlone) && !defined(WITH_ISO14443a_StandAlone)
if (BUTTON_HELD(1000) > 0)
SamyRun();
#endif
#endif
#ifdef WITH_ISO14443a
#ifdef WITH_ISO14443a_StandAlone
#if defined(WITH_ISO14443a) && defined(WITH_ISO14443a_StandAlone)
if (BUTTON_HELD(1000) > 0)
StandAloneMode14a();
#endif
#endif
}
}
}

View file

@ -16,22 +16,15 @@
#include <stddef.h>
#include "common.h"
#include "usb_cmd.h"
#include "hitag2.h"
#include "hitagS.h"
#include "mifare.h"
#include "../common/crc32.h"
#include "BigBuf.h"
#include "fpgaloader.h"
extern const uint8_t OddByteParity[256];
extern int rsamples; // = 0;
extern int tracing; // = TRUE;
extern uint8_t trigger;
// This may be used (sparingly) to declare a function to be copied to
// and executed from RAM
#define RAMFUNC __attribute((long_call, section(".ramfunc")))
/// appmain.h
void ReadMem(int addr);
void __attribute__((noreturn)) AppMain(void);
@ -78,7 +71,7 @@ void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol); // Realt
void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol);
void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol);
void CopyIOtoT55x7(uint32_t hi, uint32_t lo); // Clone an ioProx card to T5557/T5567
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble); // Clone an HID-like card to T5557/T5567
void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5);
void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo);
void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7
@ -91,6 +84,7 @@ void TurnReadLFOn();
//void T55xxReadTrace(void);
void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode);
void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd);
void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd);
void Cotag(uint32_t arg0);
/// iso14443.h
@ -101,7 +95,6 @@ void RAMFUNC SnoopIso14443b(void);
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
// Also used in iclass.c
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity);
void RAMFUNC SniffMifare(uint8_t param);
@ -110,34 +103,6 @@ void RAMFUNC SniffMifare(uint8_t param);
void EPA_PACE_Collect_Nonce(UsbCommand * c);
void EPA_PACE_Replay(UsbCommand *c);
// mifarecmd.h
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
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 MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCIdent(); // is "magic chinese" card?
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
//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);
@ -146,51 +111,5 @@ 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);
/// iso15693.h
void RecordRawAdcSamplesIso15693(void);
void AcquireRawAdcSamplesIso15693(void);
void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg
void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox
void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox
void SetDebugIso15693(uint32_t flag);
/// iclass.h
void RAMFUNC SnoopIClass(void);
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void ReaderIClass(uint8_t arg0);
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
void IClass_iso14443A_GetPublic(uint8_t arg0);
void iClass_Authentication(uint8_t *MAC);
void iClass_WriteBlock(uint8_t blockNo, uint8_t *data);
void iClass_ReadBlk(uint8_t blockNo);
bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata);
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);
/// util.h
void HfSnoop(int , int);
#endif

View file

@ -15,7 +15,7 @@
#include "iso14443a.h"
#include "iso14443b.h"
#include "epa.h"
#include "cmd.h"
#include "usb_cdc.h"
#include "fpgaloader.h"
#include "string.h"
#include "util.h"
@ -116,7 +116,7 @@ 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);
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
break;
case 'b':
return iso14443b_apdu(apdu, length, response);
@ -453,20 +453,17 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
//-----------------------------------------------------------------------------
// Perform the PACE protocol by replaying given APDUs
//-----------------------------------------------------------------------------
void EPA_PACE_Replay(UsbCommand *c)
{
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 an APDU has been passed, just save it
if (c->arg[0] != 0) {
// make sure it's not too big
if(c->arg[2] > apdus_replay[c->arg[0] - 1].len)
{
if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) {
cmd_send(CMD_ACK, 1, 0, 0, NULL, 0);
return;
}
memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1],
c->d.asBytes,
c->arg[2]);
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];

View file

@ -115,8 +115,7 @@ void SetupSpi(int mode)
// Set up the synchronous serial port with the set of options that fits
// the FPGA mode. Both RX and TX are always enabled.
//-----------------------------------------------------------------------------
void FpgaSetupSsc(uint8_t FPGA_mode)
{
void FpgaSetupSsc(uint16_t FPGA_mode) {
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
@ -130,20 +129,20 @@ void FpgaSetupSsc(uint8_t FPGA_mode)
// Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts when TX starts, data changes
// on RX clock rising edge, sampled on falling edge
// RX clock comes from TX clock, RX starts on Transmit Start,
// data and frame signal is sampled on falling edge of RK
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER_RX_XCORR) {
if ((FPGA_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// TX clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync
// TX clock comes from TK pin, no clock output, outputs change on rising edge of TK,
// TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
@ -158,15 +157,14 @@ void FpgaSetupSsc(uint8_t FPGA_mode)
// ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed.
//-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count)
{
bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) {
if (buf == NULL) return false;
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
return true;
}
@ -417,8 +415,10 @@ void FpgaDownloadAndGo(int bitstream_version)
uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00};
// check whether or not the bitstream is already loaded
if (downloaded_bitstream == bitstream_version)
if (downloaded_bitstream == bitstream_version) {
FpgaEnableTracing();
return;
}
// make sure that we have enough memory to decompress
BigBuf_free(); BigBuf_Clear_ext(false);
@ -448,22 +448,32 @@ void FpgaDownloadAndGo(int bitstream_version)
// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
// where C is the 4 bit command and D is the 12 bit data
//-----------------------------------------------------------------------------
void FpgaSendCommand(uint16_t cmd, uint16_t v)
{
void FpgaSendCommand(uint16_t cmd, uint16_t v) {
SetupSpi(SPI_FPGA_MODE);
AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // write the data to be sent
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data
}
//-----------------------------------------------------------------------------
// Write the FPGA setup word (that determines what mode the logic is in, read
// vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to
// avoid changing this function's occurence everywhere in the source code.
//-----------------------------------------------------------------------------
void FpgaWriteConfWord(uint8_t v)
{
void FpgaWriteConfWord(uint16_t v) {
FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);
}
//-----------------------------------------------------------------------------
// enable/disable FPGA internal tracing
//-----------------------------------------------------------------------------
void FpgaEnableTracing(void) {
FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 1);
}
void FpgaDisableTracing(void) {
FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 0);
}
//-----------------------------------------------------------------------------
// Set up the CMOS switches that mux the ADC: four switches, independently
// closable, but should only close one at a time. Not an FPGA thing, but

View file

@ -17,13 +17,15 @@
#include <stdbool.h>
void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v);
void FpgaWriteConfWord(uint16_t v);
void FpgaDownloadAndGo(int bitstream_version);
void FpgaSetupSsc(uint8_t mode);
void FpgaSetupSsc(uint16_t mode);
void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count);
void Fpga_print_status();
int FpgaGetCurrent();
void FpgaEnableTracing(void);
void FpgaDisableTracing(void);
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
void SetAdcMuxFor(uint32_t whichGpio);
@ -33,34 +35,53 @@ void SetAdcMuxFor(uint32_t whichGpio);
#define FPGA_BITSTREAM_HF 2
// 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_CMD_MASK 0xF000
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<5)
#define FPGA_CMD_SET_CONFREG (1<<12)
// LF
#define FPGA_CMD_SET_DIVISOR (2<<12)
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD (3<<12)
// HF
#define FPGA_CMD_TRACE_ENABLE (2<<12)
// Definitions for the FPGA configuration word.
#define FPGA_MAJOR_MODE_MASK 0x01C0
// LF
#define FPGA_MAJOR_MODE_LF_ADC (0<<6)
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<6)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<6)
// HF
#define FPGA_MAJOR_MODE_HF_READER (0<<6)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6)
#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6)
#define FPGA_MAJOR_MODE_HF_SNOOP (3<<6)
#define FPGA_MAJOR_MODE_HF_GET_TRACE (4<<6)
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<6)
#define FPGA_MINOR_MODE_MASK 0x003F
// Options for LF_ADC
#define FPGA_LF_ADC_READER_FIELD (1<<0)
// Options for LF_EDGE_DETECT
#define FPGA_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)
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (2<<0)
// Options for the HF reader
#define FPGA_HF_READER_MODE_RECEIVE_IQ (0<<0)
#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE (1<<0)
#define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0)
#define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0)
#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0)
#define FPGA_HF_READER_MODE_SNOOP_IQ (5<<0)
#define FPGA_HF_READER_MODE_SNOOP_AMPLITUDE (6<<0)
#define FPGA_HF_READER_MODE_SNOOP_PHASE (7<<0)
#define FPGA_HF_READER_MODE_SEND_JAM (8<<0)
#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4)
#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<4)
#define FPGA_HF_READER_SUBCARRIER_212_KHZ (2<<4)
// Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0)
#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0)

View file

@ -1,10 +1,22 @@
//-----------------------------------------------------------------------------
// piwi, 2019
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to get sample data from FPGA.
//-----------------------------------------------------------------------------
#include "hfsnoop.h"
#include "proxmark3.h"
#include "apps.h"
#include "BigBuf.h"
#include "util.h"
#include "usb_cdc.h" // for usb_poll_validate_length
static void RAMFUNC optimizedSnoop(void);
#include "apps.h"
#include "usb_cdc.h"
#include "fpga.h"
#include "fpgaloader.h"
static void RAMFUNC optimizedSnoop(void)
{
@ -74,3 +86,33 @@ void HfSnoop(int samplesToSkip, int triggersToSkip)
LED_D_OFF();
}
void HfPlot(void)
{
uint8_t *buf = ToSend;
uint8_t *this_buf = buf;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE);
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = USB_CMD_DATA_SIZE; // transfer this many samples
buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM
LED_B_ON();
for(size_t i = 0; i < FPGA_TRACE_SIZE; i += USB_CMD_DATA_SIZE) {
// prepare next DMA transfer:
uint8_t *next_buf = buf + ((i + USB_CMD_DATA_SIZE) % (2 * USB_CMD_DATA_SIZE));
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf;
AT91C_BASE_PDC_SSC->PDC_RNCR = USB_CMD_DATA_SIZE;
size_t len = MIN(FPGA_TRACE_SIZE - i, USB_CMD_DATA_SIZE);
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX))) ; // wait for DMA transfer to complete
cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, i, len, FPGA_TRACE_SIZE, this_buf, len);
this_buf = next_buf;
}
// Trigger a finish downloading signal with an ACK frame
cmd_send(CMD_ACK, 1, 0, FPGA_TRACE_SIZE, 0, 0);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}

17
armsrc/hfsnoop.h Normal file
View file

@ -0,0 +1,17 @@
//-----------------------------------------------------------------------------
// piwi, 2019
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to get sample data from FPGA.
//-----------------------------------------------------------------------------
#ifndef HFSNOOP_H__
#define HFSNOOP_H__
void HfSnoop(int samplesToSkip, int triggersToSkip);
void HfPlot(void);
#endif

File diff suppressed because it is too large Load diff

24
armsrc/hitag2.h Normal file
View file

@ -0,0 +1,24 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Hitag2 emulation
//
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// (c) 2012 Roel Verdult
//-----------------------------------------------------------------------------
#ifndef HITAG2_H__
#define HITAG2_H__
#include <stdint.h>
#include <stdbool.h>
#include "hitag.h"
extern void SnoopHitag(uint32_t type);
extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data);
extern void ReaderHitag(hitag_function htf, hitag_data* htd);
extern void WriterHitag(hitag_function htf, hitag_data* htd, int page);
#endif

File diff suppressed because it is too large Load diff

26
armsrc/hitagS.h Normal file
View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// HitagS emulation (preliminary test version)
//
// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg
// <info@os-s.de>
//-----------------------------------------------------------------------------
// Some code was copied from Hitag2.c
//-----------------------------------------------------------------------------
#ifndef HITAGS_H__
#define HITAGS_H__
#include <stdint.h>
#include <stdbool.h>
#include "hitag.h"
void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock);
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t* data);
void WritePageHitagS(hitag_function htf, hitag_data* htd, int page);
void check_challenges_cmd(bool file_given, uint8_t* data, uint64_t tagMode);
#endif

View file

@ -18,13 +18,15 @@
#include "mifareutil.h" // for MF_DBGLEVEL
#include "BigBuf.h"
#include "apps.h"
#include "usb_cdc.h"
#include "util.h"
#ifdef WITH_SMARTCARD
#include "smartcard.h"
#endif
// 定义连接引脚
#define GPIO_RST AT91C_PIO_PA1
#define GPIO_SCL AT91C_PIO_PA5
#define GPIO_SDA AT91C_PIO_PA7
@ -49,14 +51,41 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
for (c = delay * 2; c; c--) {};
}
// 通讯延迟函数 communication delay function
// communication delay functions
#define I2C_DELAY_1CLK I2CSpinDelayClk(1)
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
#define ISO7618_MAX_FRAME 255
// try i2c bus recovery at 100kHz = 5uS high, 5uS low
static void I2C_recovery(void) {
DbpString("Performing i2c bus recovery");
// reset I2C
SDA_H; SCL_H;
//9nth cycle acts as NACK
for (int i = 0; i < 10; i++) {
SCL_H; WaitUS(5);
SCL_L; WaitUS(5);
}
//a STOP signal (SDA from low to high while CLK is high)
SDA_L; WaitUS(5);
SCL_H; WaitUS(2);
SDA_H; WaitUS(2);
bool isok = (SCL_read && SDA_read);
if (!SDA_read)
DbpString("I2C bus recovery error: SDA still LOW");
if (!SCL_read)
DbpString("I2C bus recovery error: SCL still LOW");
if (isok)
DbpString("I2C bus recovery complete");
}
static void I2C_init(void) {
// Configure reset pin
AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; // disable pull up resistor
@ -72,10 +101,13 @@ static void I2C_init(void) {
// configure all three pins as output, controlled by PIOA
AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
bool isok = (SCL_read && SDA_read);
if ( !isok )
I2C_recovery();
}
// 设置复位状态
// set the reset state
static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) {
if (LineRST)
@ -94,19 +126,19 @@ static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA
LOW(GPIO_SDA);
}
// 复位进入主程序
// Reset the SIM_Adapter, then enter the main program
// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter.
static void I2C_Reset_EnterMainProgram(void) {
I2C_SetResetStatus(0, 0, 0); // 拉低复位线
SpinDelay(30);
I2C_SetResetStatus(1, 0, 0); // 解除复位
SpinDelay(30);
I2C_SetResetStatus(1, 1, 1); // 拉高数据线
SpinDelay(10);
StartTicks();
I2C_init();
I2C_SetResetStatus(0, 0, 0);
WaitMS(30);
I2C_SetResetStatus(1, 0, 0);
WaitMS(30);
I2C_SetResetStatus(1, 1, 1);
WaitMS(10);
}
// 等待时钟变高
// Wait for the clock to go High.
static bool WaitSCL_H_delay(uint32_t delay) {
while (delay--) {
@ -184,7 +216,8 @@ static void I2C_SendByte(uint8_t data) {
uint8_t bits = 8;
while (bits--) {
SCL_L; I2C_DELAY_1CLK;
SCL_L;
I2C_DELAY_1CLK;
if (data & 0x80)
SDA_H;
@ -205,7 +238,6 @@ static void I2C_SendByte(uint8_t data) {
}
bool I2C_is_available(void) {
I2C_init();
I2C_Reset_EnterMainProgram();
if (!I2C_Start()) // some other device is active on the bus
return true;
@ -219,33 +251,33 @@ bool I2C_is_available(void) {
}
#ifdef WITH_SMARTCARD
// 复位进入引导模式
// Reset the SIM_Adapter, then enter the bootloader program
// Reserve£ºFor firmware update.
static void I2C_Reset_EnterBootloader(void) {
I2C_SetResetStatus(0, 1, 1); // 拉低复位线
SpinDelay(100);
I2C_SetResetStatus(1, 1, 1); // 解除复位
SpinDelay(10);
I2C_SetResetStatus(0, 1, 1);
WaitMS(100);
I2C_SetResetStatus(1, 1, 1);
WaitMS(10);
}
// Wait max 300ms or until SCL goes LOW.
// Wait max 1800ms or until SCL goes LOW.
// It timeout reading response from card
// Which ever comes first
static bool WaitSCL_L_300ms(void) {
volatile uint16_t delay = 310;
bool WaitSCL_L_timeout(void){
volatile uint16_t delay = 1800;
while ( delay-- ) {
// exit on SCL LOW
if (!SCL_read)
return true;
SpinDelay(1);
WaitMS(1);
}
return (delay == 0);
}
static bool I2C_WaitForSim() {
// variable delay here.
if (!WaitSCL_L_300ms())
// wait for data from card
if (!WaitSCL_L_timeout())
return false;
// 8051 speaks with smart card.
@ -303,7 +335,7 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
do {
if (!I2C_Start())
return false;
//[C0]
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
@ -323,7 +355,6 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
return true;
}
// 写入1字节数据 (待写入数据,待写入地址,器件类型)
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ).
static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
@ -354,7 +385,6 @@ static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_addre
return true;
}
// 写入1串数据待写入数组地址待写入长度待写入地址器件类型
//Sends a string of data (Array, length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to write 256bytes)
static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
@ -393,7 +423,6 @@ static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint
return true;
}
// 读出1串数据存放读出数据待读出长度带读出地址器件类型
// read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to read 256bytes)
static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
@ -403,7 +432,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui
// extra wait 500us (514us measured)
// 200us (xx measured)
SpinDelayUs(600);
WaitUS(600);
bool bBreak = true;
uint16_t readcount = 0;
@ -462,6 +491,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui
}
I2C_Stop();
// return bytecount - first byte (which is length byte)
return --readcount;
}
@ -481,12 +511,10 @@ static int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb,
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
@ -543,12 +571,10 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
@ -577,7 +603,6 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui
void I2C_print_status(void) {
DbpString("Smart card module (ISO 7816)");
uint8_t resp[] = {0,0,0,0};
I2C_init();
I2C_Reset_EnterMainProgram();
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
if ( len > 0 )
@ -624,8 +649,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) {
// Send ATR
// start [C0 01] stop start C1 len aa bb cc stop]
I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN);
uint8_t cmd[1] = {1};
LogTrace(cmd, 1, 0, 0, NULL, true);
// wait for sim card to answer.
// 1byte = 1ms, max frame 256bytes. Should wait 256ms at least just in case.
@ -637,41 +660,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) {
if ( !sc_rx_bytes(card_ptr->atr, &len) )
return false;
uint8_t pos_td = 1;
if ( (card_ptr->atr[1] & 0x10) == 0x10) pos_td++;
if ( (card_ptr->atr[1] & 0x20) == 0x20) pos_td++;
if ( (card_ptr->atr[1] & 0x40) == 0x40) pos_td++;
// T0 indicate presence T=0 vs T=1. T=1 has checksum TCK
if ( (card_ptr->atr[1] & 0x80) == 0x80) {
pos_td++;
// 1 == T1 , presence of checksum TCK
if ( (card_ptr->atr[pos_td] & 0x01) == 0x01) {
uint8_t chksum = 0;
// xor property. will be zero when xored with chksum.
for (uint8_t i = 1; i < len; ++i)
chksum ^= card_ptr->atr[i];
if ( chksum ) {
if ( MF_DBGLEVEL > 2) DbpString("Wrong ATR checksum");
}
}
}
// for some reason we only get first byte of atr, if that is so, send dummy command to retrieve the rest of the atr
if (len == 1) {
uint8_t data[1] = {0};
I2C_BufferWrite(data, len, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
return false;
uint8_t len2 = I2C_BufferRead(card_ptr->atr + len, sizeof(card_ptr->atr) - len, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
len = len + len2;
}
card_ptr->atr_len = len;
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
@ -683,7 +671,6 @@ void SmartCardAtr(void) {
LED_D_ON();
clear_trace();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
bool isOK = GetATR( &card );
cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
@ -706,10 +693,9 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
if ((flags & SC_CONNECT)) {
I2C_init();
I2C_Reset_EnterMainProgram();
if ( !(flags & SC_NO_SELECT) ) {
if ((flags & SC_SELECT)) {
smart_card_atr_t card;
bool gotATR = GetATR( &card );
//cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
@ -718,25 +704,28 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
}
}
if ((flags & SC_RAW)) {
if ((flags & SC_RAW) || (flags & SC_RAW_T0)) {
LogTrace(data, arg1, 0, 0, NULL, true);
// Send raw bytes
// asBytes = A0 A4 00 00 02
// arg1 = len 5
I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
goto OUT;
bool res = I2C_BufferWrite(data, arg1, ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), I2C_DEVICE_ADDRESS_MAIN);
if ( !res && MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
// read bytes from module
len = ISO7618_MAX_FRAME;
sc_rx_bytes(resp, &len);
res = sc_rx_bytes(resp, &len);
if ( res ) {
LogTrace(resp, len, 0, 0, NULL, false);
} else {
len = 0;
}
}
OUT:
cmd_send(CMD_ACK, len, 0, 0, resp, len);
BigBuf_free();
set_tracing(false);
LEDsoff();
}
@ -749,7 +738,6 @@ void SmartCardUpgrade(uint64_t arg0) {
// write. Sector0, with 11,22,33,44
// erase is 128bytes, and takes 50ms to execute
I2C_init();
I2C_Reset_EnterBootloader();
bool isOK = true;
@ -777,7 +765,7 @@ void SmartCardUpgrade(uint64_t arg0) {
}
// writing takes time.
SpinDelay(50);
WaitMS(50);
// read
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
@ -799,6 +787,7 @@ void SmartCardUpgrade(uint64_t arg0) {
}
cmd_send(CMD_ACK, isOK, pos, 0, 0, 0);
LED_C_OFF();
BigBuf_free();
}
// unfinished (or not needed?)
@ -808,7 +797,6 @@ void SmartCardUpgrade(uint64_t arg0) {
void SmartCardSetClock(uint64_t arg0) {
LED_D_ON();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
// Send SIM CLC

View file

@ -23,6 +23,8 @@
#define I2C_DEVICE_CMD_SETBAUD 0x04
#define I2C_DEVICE_CMD_SIM_CLC 0x05
#define I2C_DEVICE_CMD_GETVERSION 0x06
#define I2C_DEVICE_CMD_SEND_T0 0x07
bool I2C_is_available(void);

File diff suppressed because it is too large Load diff

32
armsrc/iclass.h Normal file
View file

@ -0,0 +1,32 @@
//-----------------------------------------------------------------------------
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
// Gerhard de Koning Gans - May 2011
// Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support iClass.
//-----------------------------------------------------------------------------
#ifndef ICLASS_H__
#define ICLASS_H__
#include <stdint.h>
#include <stdbool.h>
extern void SnoopIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
extern void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void ReaderIClass(uint8_t arg0);
extern void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC);
extern void IClass_iso14443A_GetPublic(uint8_t arg0);
extern void iClass_Readcheck(uint8_t block, bool use_credit_key);
extern void iClass_Check(uint8_t *MAC);
extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data);
extern void iClass_ReadBlk(uint8_t blockNo);
extern void iClass_Dump(uint8_t blockno, uint8_t numblks);
extern void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
#endif

View file

@ -14,10 +14,12 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "cmd.h"
#include "usb_cdc.h"
#include "iso14443crc.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
@ -25,6 +27,7 @@
#include "BigBuf.h"
#include "protocols.h"
#include "parity.h"
#include "fpgaloader.h"
typedef struct {
enum {
@ -191,7 +194,7 @@ void iso14a_set_trigger(bool enable) {
void iso14a_set_timeout(uint32_t timeout) {
// adjust timeout by FPGA delays and 2 additional ssp_frames to detect SOF
iso14a_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2;
if(MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %ld (%dms)", timeout, timeout / 106);
if (MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %" PRIu32 " (%dms)", timeout, timeout / 106);
}
@ -269,29 +272,26 @@ const bool Mod_Miller_LUT[] = {
#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x000000F0) >> 4])
#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x0000000F)])
static void UartReset()
{
static void UartReset() {
Uart.state = STATE_UNSYNCD;
Uart.bitCount = 0;
Uart.len = 0; // number of decoded data bytes
Uart.parityLen = 0; // number of decoded parity bytes
Uart.shiftReg = 0; // shiftreg to hold decoded data bits
Uart.parityBits = 0; // holds 8 parity bits
Uart.startTime = 0;
Uart.endTime = 0;
}
static void UartInit(uint8_t *data, uint8_t *parity)
{
static void UartInit(uint8_t *data, uint8_t *parity) {
Uart.output = data;
Uart.parity = parity;
Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits
Uart.startTime = 0;
Uart.endTime = 0;
UartReset();
}
// use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time
static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
{
static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) {
Uart.fourBits = (Uart.fourBits << 8) | bit;
@ -318,15 +318,18 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
Uart.startTime -= Uart.syncBit;
Uart.endTime = Uart.startTime;
Uart.state = STATE_START_OF_COMMUNICATION;
LED_B_ON();
}
} else {
if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) {
if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error
LED_B_OFF();
UartReset();
} else { // Modulation in first half = Sequence Z = logic "0"
if (Uart.state == STATE_MILLER_X) { // error - must not follow after X
LED_B_OFF();
UartReset();
} else {
Uart.bitCount++;
@ -365,6 +368,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
}
} else { // no modulation in both halves - Sequence Y
if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication
LED_B_OFF();
Uart.state = STATE_UNSYNCD;
Uart.bitCount--; // last "0" was part of EOC sequence
Uart.shiftReg <<= 1; // drop it
@ -386,6 +390,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time)
}
}
if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC
LED_B_OFF();
UartReset();
} else { // a logic "0"
Uart.bitCount++;
@ -441,8 +446,7 @@ const bool Mod_Manchester_LUT[] = {
#define IsManchesterModulationNibble2(b) (Mod_Manchester_LUT[(b & 0x000F)])
static void DemodReset()
{
static void DemodReset() {
Demod.state = DEMOD_UNSYNCD;
Demod.len = 0; // number of decoded data bytes
Demod.parityLen = 0;
@ -455,16 +459,14 @@ static void DemodReset()
Demod.endTime = 0;
}
static void DemodInit(uint8_t *data, uint8_t *parity)
{
static void DemodInit(uint8_t *data, uint8_t *parity) {
Demod.output = data;
Demod.parity = parity;
DemodReset();
}
// use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time
static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time)
{
static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time) {
Demod.twoBits = (Demod.twoBits << 8) | bit;
@ -491,6 +493,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non
Demod.startTime -= Demod.syncBit;
Demod.bitCount = offset; // number of decoded data bits
Demod.state = DEMOD_MANCHESTER_DATA;
LED_C_ON();
}
}
@ -533,6 +536,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non
}
Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1);
} else { // no modulation in both halves - End of communication
LED_C_OFF();
if(Demod.bitCount > 0) { // there are some remaining data bits
Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits
Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output
@ -573,6 +577,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
// bit 1 - trigger from first reader 7-bit request
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER);
@ -625,7 +630,6 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
break;
}
LED_A_ON();
WDT_HIT();
int register readBufDataP = data - dmaBuf;
@ -657,18 +661,15 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
}
LED_A_OFF();
if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder
if(!TagIsActive) { // no need to try decoding reader data if the tag is sending
uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4);
if (MillerDecoding(readerdata, (rsamples-1)*4)) {
LED_C_ON();
// check - if there is a short 7bit request from reader
if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = true;
if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) {
triggered = true;
}
if(triggered) {
if (!LogTrace(receivedCmd,
Uart.len,
@ -682,7 +683,6 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
/* And also reset the demod code, which might have been */
/* false-triggered by the commands from the reader. */
DemodReset();
LED_B_OFF();
}
ReaderIsActive = (Uart.state != STATE_UNSYNCD);
}
@ -690,23 +690,17 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time
uint8_t tagdata = (previous_data << 4) | (*data & 0x0F);
if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) {
LED_B_ON();
if (!LogTrace(receivedResponse,
Demod.len,
Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER,
Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER,
Demod.parity,
false)) break;
if ((!triggered) && (param & 0x01)) triggered = true;
// And ready to receive another response.
DemodReset();
// And reset the Miller decoder including itS (now outdated) input buffer
UartInit(receivedCmd, receivedCmdPar);
LED_C_OFF();
}
TagIsActive = (Demod.state != DEMOD_UNSYNCD);
}
@ -720,19 +714,18 @@ void RAMFUNC SnoopIso14443a(uint8_t param) {
}
} // main cycle
DbpString("COMMAND FINISHED");
FpgaDisableSscDma();
LEDsoff();
DbpString("COMMAND FINISHED");
Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len);
Dbprintf("traceLen=%d, Uart.output[0]=%08x", BigBuf_get_traceLen(), (uint32_t)Uart.output[0]);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Prepare tag messages
//-----------------------------------------------------------------------------
static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity)
{
static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) {
ToSendReset();
// Correction bit, might be removed when not needed
@ -780,8 +773,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par
}
static void Code4bitAnswerAsTag(uint8_t cmd)
{
static void Code4bitAnswerAsTag(uint8_t cmd) {
int i;
ToSendReset();
@ -855,8 +847,7 @@ static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Pari
// Stop when button is pressed
// Or return true when command is captured
//-----------------------------------------------------------------------------
static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len)
{
static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) {
// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
// only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED
@ -886,10 +877,9 @@ static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int
}
static int EmSend4bitEx(uint8_t resp);
int EmSend4bit(uint8_t resp);
static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
int EmSendCmdEx(uint8_t *resp, uint16_t respLen);
int EmSendCmd(uint8_t *resp, uint16_t respLen);
int EmSendPrecompiledCmd(tag_response_info_t *response_info);
@ -954,8 +944,8 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_
// Main loop of simulated tag: receive commands from reader, decide what
// response to send, and send it.
//-----------------------------------------------------------------------------
void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
{
void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) {
uint8_t sak;
// The first response contains the ATQA (note: bytes are transmitted in reverse order).
@ -1124,7 +1114,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
} else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2)
p_response = &responses[4]; order = 30;
} else if(receivedCmd[0] == 0x30) { // Received a (plain) READ
EmSendCmdEx(data+(4*receivedCmd[1]),16);
EmSendCmd(data+(4*receivedCmd[1]),16);
// Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]);
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
p_response = NULL;
@ -1220,7 +1210,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
EmSendPrecompiledCmd(p_response);
}
if (!tracing) {
if (!get_tracing()) {
Dbprintf("Trace Full. Simulation stopped.");
break;
}
@ -1234,8 +1224,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data)
// prepare a delayed transfer. This simply shifts ToSend[] by a number
// of bits specified in the delay parameter.
static void PrepareDelayedTransfer(uint16_t delay)
{
static void PrepareDelayedTransfer(uint16_t delay) {
uint8_t bitmask = 0;
uint8_t bits_to_shift = 0;
uint8_t bits_shifted = 0;
@ -1264,9 +1253,9 @@ static void PrepareDelayedTransfer(uint16_t delay)
// if == 0: transfer immediately and return time of transfer
// if != 0: delay transfer until time specified
//-------------------------------------------------------------------------------------
static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing)
{
static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) {
LED_B_ON();
LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
uint32_t ThisTransferTime = 0;
@ -1286,9 +1275,6 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing
LastTimeProxToAirStart = ThisTransferTime;
}
// clear TXRDY
AT91C_BASE_SSC->SSC_THR = SEC_Y;
uint16_t c = 0;
for (;;) {
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
@ -1301,14 +1287,14 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing
}
NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME);
LED_B_OFF();
}
//-----------------------------------------------------------------------------
// Prepare reader command (in bits, support short frames) to send to FPGA
//-----------------------------------------------------------------------------
static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *parity)
{
static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *parity) {
int i, j;
int last;
uint8_t b;
@ -1391,80 +1377,93 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons
// Stop when button is pressed (return 1) or field was gone (return 2)
// Or return 0 when command is captured
//-----------------------------------------------------------------------------
int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity)
{
int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) {
uint32_t field_off_time = -1;
uint32_t samples = 0;
int ret = 0;
uint8_t b = 0;;
uint8_t dmaBuf[DMA_BUFFER_SIZE];
uint8_t *upTo = dmaBuf;
*len = 0;
uint32_t timer = 0, vtime = 0;
int analogCnt = 0;
int analogAVG = 0;
// Set ADC to read field strength
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
AT91C_BASE_ADC->ADC_MR =
ADC_MODE_PRESCALE(63) |
ADC_MODE_STARTUP_TIME(1) |
ADC_MODE_SAMPLE_HOLD_TIME(15);
AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW);
// start ADC
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
// Run a 'software UART' on the stream of incoming samples.
UartInit(received, parity);
// start ADC
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
// Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN
do {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = SEC_F;
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void) b;
}
} while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3));
while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3) - 8 - 3) /* wait */ ;
// Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen
// only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
// clear receive register, measure time of next transfer
uint32_t temp = AT91C_BASE_SSC->SSC_RHR; (void) temp;
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ;
uint32_t start_time = GetCountSspClk() & 0xfffffff8;
// Setup and start DMA.
FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE);
for(;;) {
WDT_HIT();
uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE-1);
if (BUTTON_PRESS()) return 1;
if (behindBy == 0) continue;
// test if the field exists
b = *upTo++;
if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; // start reading the circular buffer from the beginning
if(behindBy > (9*DMA_BUFFER_SIZE/10)) {
Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
ret = 1;
break;
}
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers
}
if (BUTTON_PRESS()) {
ret = 1;
break;
}
// check reader's HF field
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) {
analogCnt++;
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW];
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
if (analogCnt >= 32) {
if ((MAX_ADC_HF_VOLTAGE_LOW * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
vtime = GetTickCount();
if (!timer) timer = vtime;
// 50ms no field --> card to idle state
if (vtime - timer > 50) return 2;
} else
if (timer) timer = 0;
analogCnt = 0;
analogAVG = 0;
if ((MAX_ADC_HF_VOLTAGE_LOW * AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]) >> 10 < MF_MINFIELDV) {
if (GetTickCount() - field_off_time > 50) {
ret = 2; // reader has switched off HF field for more than 50ms. Timeout
break;
}
} else {
field_off_time = GetTickCount(); // HF field is still there. Reset timer
}
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; // restart ADC
}
// receive and test the miller decoding
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
if(MillerDecoding(b, 0)) {
if (MillerDecoding(b, start_time + samples*8)) {
*len = Uart.len;
EmLogTraceReader();
return 0;
}
ret = 0;
break;
}
samples++;
}
FpgaDisableSscDma();
return ret;
}
static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen)
{
static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
LED_C_ON();
uint8_t b;
uint16_t i = 0;
bool correctionNeeded;
@ -1492,7 +1491,6 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen)
}
// clear receiving shift register and holding register
while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY));
b = AT91C_BASE_SSC->SSC_RHR; (void) b;
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY));
b = AT91C_BASE_SSC->SSC_RHR; (void) b;
@ -1517,40 +1515,29 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen)
}
}
LED_C_OFF();
return 0;
}
static int EmSend4bitEx(uint8_t resp){
int EmSend4bit(uint8_t resp){
Code4bitAnswerAsTag(resp);
int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
// do the tracing for the previous reader request and this tag answer:
// Log this tag answer and fix timing of previous reader command:
EmLogTraceTag(&resp, 1, NULL, LastProxToAirDuration);
return res;
}
int EmSend4bit(uint8_t resp){
return EmSend4bitEx(resp);
}
static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
CodeIso14443aAsTagPar(resp, respLen, par);
int res = EmSendCmd14443aRaw(ToSend, ToSendMax);
// do the tracing for the previous reader request and this tag answer:
// Log this tag answer and fix timing of previous reader command:
EmLogTraceTag(resp, respLen, par, LastProxToAirDuration);
return res;
}
int EmSendCmdEx(uint8_t *resp, uint16_t respLen){
uint8_t par[MAX_PARITY_SIZE];
GetParity(resp, respLen, par);
return EmSendCmdExPar(resp, respLen, par);
}
int EmSendCmd(uint8_t *resp, uint16_t respLen){
uint8_t par[MAX_PARITY_SIZE];
GetParity(resp, respLen, par);
@ -1565,7 +1552,7 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){
int EmSendPrecompiledCmd(tag_response_info_t *response_info) {
int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n);
// do the tracing for the previous reader request and this tag answer:
// Log this tag answer and fix timing of previous reader command:
EmLogTraceTag(response_info->response, response_info->response_n, &(response_info->par), response_info->ProxToAirDuration);
return ret;
}
@ -1576,8 +1563,7 @@ int EmSendPrecompiledCmd(tag_response_info_t *response_info) {
// If a response is captured return true
// If it takes too long return false
//-----------------------------------------------------------------------------
static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset)
{
static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) {
uint32_t c;
// Set FPGA mode to "reader listen mode", no modulation (listen
@ -1609,8 +1595,8 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive
}
void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing)
{
void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) {
CodeIso14443aBitsAsReaderPar(frame, bits, par);
// Send command to tag
@ -1619,20 +1605,16 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t
LED_A_ON();
// Log reader command in trace buffer
if (tracing) {
LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true);
}
}
void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing)
{
void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing) {
ReaderTransmitBitsPar(frame, len*8, par, timing);
}
static void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
{
static void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) {
// Generate parity and redirect
uint8_t par[MAX_PARITY_SIZE];
GetParity(frame, len/8, par);
@ -1640,8 +1622,7 @@ static void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing)
}
void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing)
{
void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) {
// Generate parity and redirect
uint8_t par[MAX_PARITY_SIZE];
GetParity(frame, len, par);
@ -1649,22 +1630,17 @@ void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing)
}
static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity)
{
static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity) {
if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, offset)) return false;
if (tracing) {
LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
}
return Demod.len;
}
int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity)
{
int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) {
if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return false;
if (tracing) {
LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false);
}
return Demod.len;
}
@ -1700,7 +1676,7 @@ static void iso14a_set_ATS_times(uint8_t *ats) {
static int GetATQA(uint8_t *resp, uint8_t *resp_par) {
#define WUPA_RETRY_TIMEOUT 10 // 10ms
uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP
uint8_t wupa[] = {ISO14443A_CMD_WUPA}; // 0x26 - REQA 0x52 - WAKE-UP
uint32_t save_iso14a_timeout = iso14a_get_timeout();
iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer.
@ -1727,13 +1703,13 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) {
// if anticollision is false, then the UID must be provided in uid_ptr[]
// and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID)
// requests ATS unless no_rats is true
int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) {
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) {
uint8_t sel_all[] = { 0x93,0x20 };
uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0
uint8_t resp[MAX_FRAME_SIZE]; // theoretically. A usual RATS will be much smaller
uint8_t resp_par[MAX_PARITY_SIZE];
byte_t uid_resp[4];
uint8_t uid_resp[4];
size_t uid_resp_len;
uint8_t sak = 0x04; // cascade uid
@ -1769,7 +1745,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
// OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in
// which case we need to make a cascade 2 request and select - this is a long UID
// While the UID is not complete, the 3nd bit (from the right) is set in the SAK.
// While the UID is not complete, the 3rd bit (from the right) is set in the SAK.
for (; sak & 0x04; cascade_level++) {
// SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97)
sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2;
@ -1777,7 +1753,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
if (anticollision) {
// SELECT_ALL
ReaderTransmit(sel_all, sizeof(sel_all), NULL);
if (!ReaderReceive(resp, resp_par)) return 0;
if (!ReaderReceive(resp, resp_par)) {
return 0;
}
if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit
memset(uid_resp, 0, 4);
@ -1799,7 +1777,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
}
collision_answer_offset = uid_resp_bits%8;
ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL);
if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) return 0;
if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) {
return 0;
}
}
// finally, add the last bits and BCC of the UID
for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) {
@ -1833,7 +1813,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
ReaderTransmit(sel_uid, sizeof(sel_uid), NULL);
// Receive the SAK
if (!ReaderReceive(resp, resp_par)) return 0;
if (!ReaderReceive(resp, resp_par)) {
return 0;
}
sak = resp[0];
// Test if more parts of the uid are coming
@ -1868,7 +1850,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
AppendCrc14443a(rats, 2);
ReaderTransmit(rats, sizeof(rats), NULL);
if (!(len = ReaderReceive(resp, resp_par))) return 0;
if (!(len = ReaderReceive(resp, resp_par))) {
return 0;
}
if(p_hi14a_card) {
memcpy(p_hi14a_card->ats, resp, len);
@ -1902,11 +1886,22 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
// Set ADC to read field strength
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
AT91C_BASE_ADC->ADC_MR =
ADC_MODE_PRESCALE(63) |
ADC_MODE_STARTUP_TIME(1) |
ADC_MODE_SAMPLE_HOLD_TIME(15);
AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW);
// Start the timer
StartCountSspClk();
DemodReset();
UartReset();
LastTimeProxToAirStart = 0;
FpgaSendQueueDelay = 0;
LastProxToAirDuration = 20; // arbitrary small value. Avoid lock in EmGetCmd()
NextTransferTime = 2*DELAY_ARM2AIR_AS_READER;
iso14a_set_timeout(1060); // 10ms default
}
@ -1935,15 +1930,24 @@ b8 b7 b6 b5 b4 b3 b2 b1
b5,b6 = 00 - DESELECT
11 - WTX
*/
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) {
uint8_t parity[MAX_PARITY_SIZE];
uint8_t real_cmd[cmd_len + 4];
if (cmd_len) {
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00)
if (send_chaining) {
real_cmd[0] |= 0x10;
}
// put block number into the PCB
real_cmd[0] |= iso14_pcb_blocknum;
memcpy(real_cmd + 1, cmd, cmd_len);
} else {
// R-block. ACK
real_cmd[0] = 0xA2; // r-block + ACK
real_cmd[0] |= iso14_pcb_blocknum;
}
AppendCrc14443a(real_cmd, cmd_len + 1);
ReaderTransmit(real_cmd, cmd_len + 3, NULL);
@ -1955,7 +1959,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
return 0; //DATA LINK ERROR
} else {
// S-Block WTX
while((data_bytes[0] & 0xF2) == 0xF2) {
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
uint32_t save_iso14a_timeout = iso14a_get_timeout();
// temporarily increase timeout
iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT));
@ -1983,6 +1987,10 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
iso14_pcb_blocknum ^= 1;
}
// if we received I-block with chaining we need to send ACK and receive another block of data
if (res)
*res = data_bytes[0];
// crc check
if (len >= 3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) {
return -1;
@ -1990,11 +1998,13 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
}
if (len) {
// cut frame byte
len -= 1;
// memmove(data_bytes, data_bytes + 1, len);
for (int i = 0; i < len; i++)
data_bytes[i] = data_bytes[i + 1];
}
return len;
}
@ -2004,15 +2014,15 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
// Read an ISO 14443a tag. Send out commands and store answers.
//
//-----------------------------------------------------------------------------
void ReaderIso14443a(UsbCommand *c)
{
void ReaderIso14443a(UsbCommand *c) {
iso14a_command_t param = c->arg[0];
uint8_t *cmd = c->d.asBytes;
size_t len = c->arg[1] & 0xffff;
size_t lenbits = c->arg[1] >> 16;
uint32_t timeout = c->arg[2];
uint32_t arg0 = 0;
byte_t buf[USB_CMD_DATA_SIZE] = {0};
uint8_t buf[USB_CMD_DATA_SIZE] = {0};
uint8_t par[MAX_PARITY_SIZE];
bool cantSELECT = false;
@ -2038,9 +2048,9 @@ void ReaderIso14443a(UsbCommand *c)
// 1 - all is OK with ATS, 2 - without ATS
cantSELECT = true;
}
FpgaDisableTracing();
LED_B_ON();
cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t));
cmd_send(CMD_NACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t));
LED_B_OFF();
}
}
@ -2050,9 +2060,11 @@ void ReaderIso14443a(UsbCommand *c)
}
if (param & ISO14A_APDU && !cantSELECT) {
arg0 = iso14_apdu(cmd, len, buf);
uint8_t res;
arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res);
FpgaDisableTracing();
LED_B_ON();
cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf));
LED_B_OFF();
}
@ -2092,6 +2104,7 @@ void ReaderIso14443a(UsbCommand *c)
}
}
arg0 = ReaderReceive(buf, par);
FpgaDisableTracing();
LED_B_ON();
cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
@ -2408,6 +2421,8 @@ void ReaderMifare(bool first_try)
}
}
FpgaDisableTracing();
uint8_t buf[32];
memcpy(buf + 0, uid, 4);
num_to_bytes(nt, 4, buf + 4);
@ -2436,6 +2451,8 @@ void RAMFUNC SniffMifare(uint8_t param) {
// C(red) A(yellow) B(green)
LEDsoff();
LED_A_ON();
// init trace buffer
clear_trace();
set_tracing(true);
@ -2471,8 +2488,6 @@ void RAMFUNC SniffMifare(uint8_t param) {
// Setup for the DMA.
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer.
LED_D_OFF();
// init sniffer
MfSniffInit();
@ -2484,7 +2499,6 @@ void RAMFUNC SniffMifare(uint8_t param) {
break;
}
LED_A_ON();
WDT_HIT();
if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time
@ -2530,15 +2544,11 @@ void RAMFUNC SniffMifare(uint8_t param) {
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
}
LED_A_OFF();
if (sniffCounter & 0x01) {
if(!TagIsActive) { // no need to try decoding tag data if the reader is sending
uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4);
if(MillerDecoding(readerdata, (sniffCounter-1)*4)) {
LED_B_ON();
LED_C_OFF();
if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, true)) break;
@ -2554,8 +2564,6 @@ void RAMFUNC SniffMifare(uint8_t param) {
if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending
uint8_t tagdata = (previous_data << 4) | (*data & 0x0F);
if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) {
LED_B_OFF();
LED_C_ON();
if (MfSniffLogic(receivedResponse, Demod.len, Demod.parity, Demod.bitCount, false)) break;
@ -2577,11 +2585,13 @@ void RAMFUNC SniffMifare(uint8_t param) {
} // main cycle
FpgaDisableTracing();
FpgaDisableSscDma();
LEDsoff();
DbpString("COMMAND FINISHED.");
FpgaDisableSscDma();
MfSniffEnd();
Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len);
LEDsoff();
}

View file

@ -13,6 +13,7 @@
#ifndef __ISO14443A_H
#define __ISO14443A_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "usb_cmd.h"
@ -31,7 +32,7 @@ extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
extern void AppendCrc14443a(uint8_t *data, int len);
extern void RAMFUNC SnoopIso14443a(uint8_t param);
extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t *data);
extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t *data);
extern void ReaderIso14443a(UsbCommand *c);
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
@ -41,7 +42,6 @@ extern void ReaderMifare(bool first_try);
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen);
extern int EmSend4bit(uint8_t resp);
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
@ -49,8 +49,9 @@ extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
extern void iso14a_set_trigger(bool enable);
extern void iso14a_set_timeout(uint32_t timeout);
extern uint32_t iso14a_get_timeout(void);
#endif /* __ISO14443A_H */

View file

@ -10,14 +10,18 @@
// the `fake tag' modes.
//-----------------------------------------------------------------------------
#include "iso14443b.h"
#include "proxmark3.h"
#include "apps.h"
#include "usb_cdc.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "fpgaloader.h"
#include "BigBuf.h"
#define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high?
#define RECEIVE_SAMPLES_TIMEOUT 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA
#define ISO14443B_DMA_BUFFER_SIZE 128
// PCB Block number for APDUs
@ -325,6 +329,7 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len)
//-----------------------------------------------------------------------------
void SimulateIso14443bTag(void)
{
LED_A_ON();
// the only commands we understand is WUPB, AFI=0, Select All, N=1:
static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; // WUPB
// ... and REQB, AFI=0, Normal Request, N=1:
@ -386,10 +391,7 @@ void SimulateIso14443bTag(void)
break;
}
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(receivedCmd, len, 0, 0, parity, true);
}
LogTrace(receivedCmd, len, 0, 0, NULL, true);
// Good, look at the command now.
if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0)
@ -463,12 +465,12 @@ void SimulateIso14443bTag(void)
}
// trace the response:
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(resp, respLen, 0, 0, parity, false);
}
LogTrace(resp, respLen, 0, 0, NULL, false);
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_A_OFF();
}
//=============================================================================
@ -585,9 +587,10 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
Demod.state = DEMOD_UNSYNCD;
} else {
LED_C_ON(); // Got SOF
Demod.state = DEMOD_AWAITING_START_BIT;
Demod.posCount = 0;
Demod.bitCount = 0;
Demod.len = 0;
Demod.state = DEMOD_AWAITING_START_BIT;
/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented.
Demod.metricN = 0;
Demod.metric = 0;
@ -606,11 +609,14 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
MAKE_SOFT_DECISION();
if (v > 0) {
if (Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
Demod.state = DEMOD_UNSYNCD;
LED_C_OFF();
if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass
return true;
} else {
Demod.state = DEMOD_UNSYNCD;
}
}
} else { // start bit detected
Demod.bitCount = 0;
Demod.posCount = 1; // this was the first half
Demod.thisBit = v;
Demod.shiftReg = 0;
@ -647,6 +653,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
uint8_t b = (s >> 1);
Demod.output[Demod.len] = b;
Demod.len++;
Demod.bitCount = 0;
Demod.state = DEMOD_AWAITING_START_BIT;
} else {
Demod.state = DEMOD_UNSYNCD;
@ -692,8 +699,8 @@ static void DemodInit(uint8_t *data)
* Demodulate the samples we received from the tag, also log to tracebuffer
* quiet: set to 'true' to disable debug output
*/
static void GetSamplesFor14443bDemod(int n, bool quiet)
{
static int GetSamplesFor14443bDemod(int timeout, bool quiet) {
int ret = 0;
int maxBehindBy = 0;
bool gotFrame = false;
int lastRxCounter, samples = 0;
@ -716,7 +723,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY))
// Setup and start DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
uint16_t *upTo = dmaBuf;
@ -725,7 +732,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
// Signal field is ON with the appropriate LED:
LED_D_ON();
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
for(;;) {
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
@ -750,11 +757,14 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
samples++;
if (Handle14443bSamplesDemod(ci, cq)) {
ret = Demod.len;
gotFrame = true;
break;
}
if(samples > n) {
if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) {
ret = -1;
LED_C_OFF();
break;
}
}
@ -762,11 +772,14 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
FpgaDisableSscDma();
if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
//Tracing
if (tracing && Demod.len > 0) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, 0, 0, parity, false);
if (ret < 0) {
return ret;
}
//Tracing
LogTrace(Demod.output, Demod.len, 0, 0, NULL, false);
return ret;
}
@ -775,28 +788,21 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
//-----------------------------------------------------------------------------
static void TransmitFor14443b(void)
{
int c;
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
// Signal field is ON with the appropriate Red LED
LED_D_ON();
// Signal we are transmitting with the Green LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
LED_B_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
c = 0;
for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++;
if(c >= ToSendMax) {
break;
}
for(int c = 0; c < ToSendMax; c++) {
uint8_t data = ToSend[c];
for (int i = 0; i < 8; i++) {
uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff;
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
AT91C_BASE_SSC->SSC_THR = send_word;
while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ;
AT91C_BASE_SSC->SSC_THR = send_word;
data <<= 1;
}
WDT_HIT();
}
LED_B_OFF(); // Finished sending
LED_B_OFF();
}
@ -858,17 +864,14 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
{
CodeIso14443bAsReader(cmd, len);
TransmitFor14443b();
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(cmd,len, 0, 0, parity, true);
}
LogTrace(cmd,len, 0, 0, NULL, true);
}
/* Sends an APDU to the tag
* TODO: check CRC and preamble
*/
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response)
{
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) {
LED_A_ON();
uint8_t message_frame[message_length + 4];
// PCB
message_frame[0] = 0x0A | pcb_blocknum;
@ -882,18 +885,19 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo
// send
CodeAndTransmit14443bAsReader(message_frame, message_length + 4);
// get response
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if(Demod.len < 3)
{
int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
FpgaDisableTracing();
if (ret < 3) {
LED_A_OFF();
return 0;
}
// TODO: Check CRC
// copy response contents
if(response != NULL)
{
if (response != NULL) {
memcpy(response, Demod.output, Demod.len);
}
return Demod.len;
LED_A_OFF();
return ret;
}
/* Perform the ISO 14443 B Card Selection procedure
@ -912,10 +916,9 @@ int iso14443b_select_card()
// first, wake up the tag
CodeAndTransmit14443bAsReader(wupb, sizeof(wupb));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
// ATQB too short?
if (Demod.len < 14)
{
if (ret < 14) {
return 2;
}
@ -927,10 +930,9 @@ int iso14443b_select_card()
attrib[7] = Demod.output[10] & 0x0F;
ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10);
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
// Answer to ATTRIB too short?
if(Demod.len < 3)
{
if (ret < 3) {
return 2;
}
// reset PCB block number
@ -942,13 +944,13 @@ int iso14443b_select_card()
void iso14443b_setup() {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Signal field is on with the appropriate LED
LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
DemodReset();
UartReset();
@ -965,6 +967,7 @@ void iso14443b_setup() {
//-----------------------------------------------------------------------------
void ReadSTMemoryIso14443b(uint32_t dwLast)
{
LED_A_ON();
uint8_t i = 0x00;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
@ -975,12 +978,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
SpinDelay(200);
clear_trace();
@ -989,12 +992,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
// First command: wake up the tag using the INITIATE command
uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b};
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len == 0) {
DbpString("No response from tag");
LED_D_OFF();
if (ret < 0) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
DbpString("No response from tag");
LEDsoff();
return;
} else {
Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x",
@ -1007,26 +1010,26 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[1] = Demod.output[0];
ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 3) {
Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
LEDsoff();
return;
}
// Check the CRC of the answer:
ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
DbpString("CRC Error reading select response.");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
DbpString("CRC Error reading select response.");
LEDsoff();
return;
}
// Check response from the tag: should be the same UID as the command we just sent:
if (cmd1[1] != Demod.output[0]) {
Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]);
LEDsoff();
return;
}
@ -1035,11 +1038,11 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[0] = 0x0B;
ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);
CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 10) {
Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
LED_D_OFF();
ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (ret != 10) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
LEDsoff();
return;
}
// The check the CRC of the answer (use cmd1 as temporary variable):
@ -1066,11 +1069,11 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[1] = i;
ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 6) { // Check if we got an answer from the tag
DbpString("Expected 6 bytes from tag, got less...");
LED_D_OFF();
ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (ret != 6) { // Check if we got an answer from the tag
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
DbpString("Expected 6 bytes from tag, got less...");
LEDsoff();
return;
}
// The check the CRC of the answer (use cmd1 as temporary variable):
@ -1090,8 +1093,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
i++;
}
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
@ -1114,6 +1117,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
*/
void RAMFUNC SnoopIso14443b(void)
{
LED_A_ON();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BigBuf_free();
@ -1141,19 +1145,18 @@ void RAMFUNC SnoopIso14443b(void)
Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE);
Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE);
// Signal field is off, no reader signal, no tag signal
LEDsoff();
// Signal field is off
LED_D_OFF();
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNOOP_IQ);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup for the DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
uint8_t parity[MAX_PARITY_SIZE];
bool TagIsActive = false;
bool ReaderIsActive = false;
@ -1198,9 +1201,7 @@ void RAMFUNC SnoopIso14443b(void)
if (!TagIsActive) { // no need to try decoding reader data if the tag is sending
if(Handle14443bUartBit(ci & 0x01)) {
triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
}
LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true);
/* And ready to receive another command. */
UartReset();
/* And also reset the demod code, which might have been */
@ -1209,9 +1210,7 @@ void RAMFUNC SnoopIso14443b(void)
}
if(Handle14443bUartBit(cq & 0x01)) {
triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
}
LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true);
/* And ready to receive another command. */
UartReset();
/* And also reset the demod code, which might have been */
@ -1222,14 +1221,9 @@ void RAMFUNC SnoopIso14443b(void)
}
if (!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered
if(Handle14443bSamplesDemod(ci/2, cq/2)) {
if (Handle14443bSamplesDemod(ci/2, cq/2) >= 0) {
//Use samples as a time measurement
if(tracing)
{
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, samples, samples, parity, false);
}
LogTrace(Demod.output, Demod.len, samples, samples, NULL, false);
// And ready to receive another response.
DemodReset();
}
@ -1239,13 +1233,13 @@ void RAMFUNC SnoopIso14443b(void)
}
FpgaDisableSscDma();
LEDsoff();
DbpString("Snoop statistics:");
Dbprintf(" Max behind by: %i", maxBehindBy);
Dbprintf(" Uart State: %x", Uart.state);
Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt);
Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax);
Dbprintf(" Trace length: %i", BigBuf_get_traceLen());
LEDsoff();
}
@ -1263,12 +1257,14 @@ void RAMFUNC SnoopIso14443b(void)
*/
void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[])
{
LED_A_ON();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// switch field on and give tag some time to power up
LED_D_ON();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
SpinDelay(10);
if (datalen){
@ -1277,15 +1273,20 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u
CodeAndTransmit14443bAsReader(data, datalen);
if (recv) {
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
int ret = GetSamplesFor14443bDemod(5*RECEIVE_SAMPLES_TIMEOUT, true);
FpgaDisableTracing();
uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE);
cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen);
cmd_send(CMD_ACK, ret, 0, 0, Demod.output, iLen);
}
FpgaDisableTracing();
}
if (!powerfield) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
}
LED_A_OFF();
}

View file

@ -10,12 +10,18 @@
// Routines to support ISO 14443 type B.
//-----------------------------------------------------------------------------
#ifndef __ISO14443B_H
#define __ISO14443B_H
#include "common.h"
#ifndef ISO14443B_H__
#define ISO14443B_H__
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response);
void iso14443b_setup();
int iso14443b_select_card();
#include <stdint.h>
#include <stddef.h>
extern int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response);
extern void iso14443b_setup();
extern int iso14443b_select_card();
extern void SimulateIso14443bTag(void);
extern void ReadSTMemoryIso14443b(uint32_t);
extern void SnoopIso14443b(void);
extern void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
#endif /* __ISO14443B_H */

File diff suppressed because it is too large Load diff

43
armsrc/iso15693.h Normal file
View file

@ -0,0 +1,43 @@
//-----------------------------------------------------------------------------
// Piwi - October 2018
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 15693.
//-----------------------------------------------------------------------------
#ifndef ISO15693_H__
#define ISO15693_H__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
// Delays in SSP_CLK ticks.
// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag
#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16
#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response
#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command
extern void Iso15693InitReader(void);
extern void Iso15693InitTag(void);
extern void CodeIso15693AsReader(uint8_t *cmd, int n);
extern void CodeIso15693AsTag(uint8_t *cmd, size_t len);
extern void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow);
extern int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time);
extern void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time);
extern int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time);
extern void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string);
extern void AcquireRawAdcSamplesIso15693(void);
extern void ReaderIso15693(uint32_t parameter);
extern void SimTagIso15693(uint32_t parameter, uint8_t *uid);
extern void BruteforceIso15693Afi(uint32_t speed);
extern void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]);
extern void SetTag15693Uid(uint8_t *uid);
extern void SetDebugIso15693(uint32_t flag);
extern bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
#endif

View file

@ -10,15 +10,17 @@
// LEGIC RF simulation code
//-----------------------------------------------------------------------------
#include "legicrf.h"
#include "proxmark3.h"
#include "apps.h"
#include "usb_cdc.h"
#include "util.h"
#include "string.h"
#include "legicrf.h"
#include "legic_prng.h"
#include "legic.h"
#include "crc.h"
#include "fpgaloader.h"
static legic_card_select_t card;/* metadata of currently selected card */
static crc_t legic_crc;
@ -151,7 +153,7 @@ static inline void tx_bit(bool bit) {
//-----------------------------------------------------------------------------
static void tx_frame(uint32_t frame, uint8_t len) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD);
// wait for next tx timeslot
last_frame_end += RWD_FRAME_WAIT;
@ -172,9 +174,7 @@ static void tx_frame(uint32_t frame, uint8_t len) {
}
static uint32_t rx_frame(uint8_t len) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER_FREQ);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
@ -195,9 +195,7 @@ static uint32_t rx_frame(uint8_t len) {
static bool rx_ack() {
// change fpga into rx mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER_FREQ);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
@ -257,14 +255,12 @@ static int init_card(uint8_t cardtype, legic_card_select_t *p_card) {
static void init_reader(bool clear_mem) {
// configure FPGA
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER_FREQ);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
LED_D_ON();
// configure SSC with defaults
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
// re-claim GPIO_SSC_DOUT as GPIO and enable output
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
@ -384,8 +380,9 @@ void LegicRfReader(int offset, int bytes) {
// establish shared secret and detect card type
DbpString("Reading card ...");
uint8_t card_type = setup_phase(SESSION_IV);
uint8_t result = 0;
if(init_card(card_type, &card) != 0) {
Dbprintf("No or unknown card found, aborting");
result = 1;
goto OUT;
}
@ -402,17 +399,14 @@ void LegicRfReader(int offset, int bytes) {
for(uint16_t i = 0; i < bytes; ++i) {
int16_t byte = read_byte(offset + i, card.cmdsize);
if(byte == -1) {
Dbprintf("operation failed @ 0x%03.3x", bytes);
result = 2;
goto OUT;
}
BigBuf[i] = byte;
}
// OK
Dbprintf("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize);
Dbprintf("'data hexsamples %d' to view results", (bytes+7) & ~7);
OUT:
cmd_send(CMD_ACK, result, bytes, 0, &card, sizeof(card));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_OFF();
LED_C_OFF();

View file

@ -10,16 +10,17 @@
// LEGIC RF simulation code
//-----------------------------------------------------------------------------
#include "legicrfsim.h"
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "legicrfsim.h"
#include "legic_prng.h"
#include "legic.h"
#include "crc.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "fpgaloader.h"
static uint8_t* legic_mem; /* card memory, used for sim */
static legic_card_select_t card;/* metadata of currently selected card */
@ -51,7 +52,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
#define RWD_TIME_PAUSE 4 /* 18.9us */
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */
#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */

View file

@ -17,7 +17,8 @@
#include "lfdemod.h"
#include "lfsampling.h"
#include "protocols.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "usb_cdc.h"
#include "fpgaloader.h"
/**
* Function to do a modulation and then get samples.
@ -1197,12 +1198,79 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol)
* and enlarge the gap ones.
* Q5 tags seems to have issues when these values changes.
*/
/*
// Original Timings for reference
//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds)
#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc)
#define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc)
#define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc)
#define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550
#define READ_GAP 15*8
*/
/* Q5 timing datasheet:
* Type | MIN | Typical | Max |
* Start_Gap | 10*8 | ? | 50*8 |
* Write_Gap Normal mode | 8*8 | 14*8 | 20*8 |
* Write_Gap Fast Mode | 8*8 | ? | 20*8 |
* Write_0 Normal mode | 16*8 | 24*8 | 32*8 |
* Write_1 Normal mode | 48*8 | 56*8 | 64*8 |
* Write_0 Fast Mode | 8*8 | 12*8 | 16*8 |
* Write_1 Fast Mode | 24*8 | 28*8 | 32*8 |
*/
/* T5557 timing datasheet:
* Type | MIN | Typical | Max |
* Start_Gap | 10*8 | ? | 50*8 |
* Write_Gap Normal mode | 8*8 |50-150us | 30*8 |
* Write_Gap Fast Mode | 8*8 | ? | 20*8 |
* Write_0 Normal mode | 16*8 | 24*8 | 31*8 |
* Write_1 Normal mode | 48*8 | 54*8 | 63*8 |
* Write_0 Fast Mode | 8*8 | 12*8 | 15*8 |
* Write_1 Fast Mode | 24*8 | 28*8 | 31*8 |
*/
/* T5577C timing datasheet for Fixed-Bit-Length protocol (defualt):
* Type | MIN | Typical | Max |
* Start_Gap | 8*8 | 15*8 | 50*8 |
* Write_Gap Normal mode | 8*8 | 10*8 | 20*8 |
* Write_Gap Fast Mode | 8*8 | 10*8 | 20*8 |
* Write_0 Normal mode | 16*8 | 24*8 | 32*8 |
* Write_1 Normal mode | 48*8 | 56*8 | 64*8 |
* Write_0 Fast Mode | 8*8 | 12*8 | 16*8 |
* Write_1 Fast Mode | 24*8 | 28*8 | 32*8 |
*/
// Structure to hold Timing values. In future will be simplier to add user changable timings.
typedef struct {
uint16_t START_GAP;
uint16_t WRITE_GAP;
uint16_t WRITE_0;
uint16_t WRITE_1;
uint16_t WRITE_2;
uint16_t WRITE_3;
uint16_t READ_GAP;
} T55xx_Timing;
// Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here.
T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 };
T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 };
T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 };
T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 };
// Some defines for readability
#define T55xx_DLMode_Fixed 0 // Default Mode
#define T55xx_DLMode_LLR 1 // Long Leading Reference
#define T55xx_DLMode_Leading0 2 // Leading Zero
#define T55xx_DLMode_1of4 3 // 1 of 4
#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference
// Macro for code readability
#define BitStream_Byte(X) ((X) >> 3)
#define BitStream_Bit(X) ((X) & 7)
void TurnReadLFOn(int delay) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// Give it a bit of time for the resonant antenna to settle.
@ -1210,36 +1278,179 @@ void TurnReadLFOn(int delay) {
}
// Write one bit to card
void T55xxWriteBit(int bit) {
if (!bit)
TurnReadLFOn(WRITE_0);
else
TurnReadLFOn(WRITE_1);
void T55xxWriteBit(int bit, T55xx_Timing *Timings) {
// If bit = 4 Send Long Leading Reference which is 138 + WRITE_0
// Dbprintf ("Bits : %d",bit);
switch (bit){
case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00
case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01
case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10
case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11
case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(WRITE_GAP);
WaitUS(Timings->WRITE_GAP);
}
// Send T5577 reset command then read stream (see if we can identify the start of the stream)
void T55xxResetRead(void) {
LED_A_ON();
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_keep_EM();
// Function to abstract an Arbitrary length byte array to store bit pattern.
// bit_array - Array to hold data/bit pattern
// start_offset - bit location to start storing new bits.
// data - upto 32 bits of data to store
// num_bits - how many bits (low x bits of data) Max 32 bits at a time
// max_len - how many bytes can the bit_array hold (ensure no buffer overflow)
// returns "Next" bit offset / bits stored (for next store)
//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len)
int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len)
{
int8_t offset;
int8_t NextOffset = start_offset;
// Check if data will fit.
if ((start_offset + num_bits) <= (max_len*8)) {
// Loop through the data and store
for (offset = (num_bits-1); offset >= 0; offset--) {
if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1
else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0
NextOffset++;
}
}
else {
// Note: This should never happen unless some code changes cause it.
// So short message for coders when testing.
Dbprintf ("T55 too many bits");
}
return NextOffset;
}
// Send one downlink command to the card
void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
/*
arg bits
xxxxxxx1 0x01 PwdMode
xxxxxx1x 0x02 Page
xxxxx1xx 0x04 testMode
xxx11xxx 0x18 downlink mode
xx1xxxxx 0x20 !reg_readmode
x1xxxxxx 0x40 called for a read, so no data packet
1xxxxxxx 0x80 reset
*/
bool PwdMode = ((arg & 0x01) == 0x01);
bool Page = (arg & 0x02);
bool testMode = ((arg & 0x04) == 0x04);
uint8_t downlink_mode = (arg >> 3) & 0x03;
bool reg_readmode = ((arg & 0x20) == 0x20);
bool read_cmd = ((arg & 0x40) == 0x40);
bool reset = (arg & 0x80);
uint8_t i = 0;
uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits)
uint8_t BitStreamLen;
T55xx_Timing *Timing;
uint8_t SendBits;
// Assigning Downlink Timeing for write
switch (downlink_mode)
{
case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break;
case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break;
case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break;
case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break;
default:
Timing = &T55xx_Timing_FixedBit;
}
// Build Bit Stream to send.
memset (BitStream,0x00,sizeof(BitStream));
BitStreamLen = 0; // Ensure 0 bit index to start.
// Add Leading 0 and 1 of 4 reference bit
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4))
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
// Add extra reference 0 for 1 of 4
if (downlink_mode == T55xx_DLMode_1of4)
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
// Add Opcode
if (reset) {
// Reset : r*) 00
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
}
else
{
if (testMode) Dbprintf("TestMODE");
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream));
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream));
if (PwdMode) {
// Leading 0 and 1 of 4 00 fixed bits if passsword used
if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) {
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream));
}
BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream));
}
// Add Lock bit 0
if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream));
// Add Data if a write command
if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream));
// Add Address
if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream));
}
// Send Bits to T55xx
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
StartTicks();
// make sure tag is fully powered up...
WaitMS(5);
// Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(START_GAP);
WaitUS(Timing->START_GAP);
// reset tag - op code 00
T55xxWriteBit(0);
T55xxWriteBit(0);
// If long leading 0 send long reference pulse
if (downlink_mode == T55xx_DLMode_LLR)
T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference
TurnReadLFOn(READ_GAP);
if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time
for ( i = 0; i < BitStreamLen-1; i+=2 ) {
SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i
SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1;
T55xxWriteBit (SendBits & 3,Timing);
}
}
else {
for (i = 0; i < BitStreamLen; i++) {
SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i));
T55xxWriteBit (SendBits & 1,Timing);
}
}
}
// Send T5577 reset command then read stream (see if we can identify the start of the stream)
void T55xxResetRead(void) {
LED_A_ON();
// send r* 00
uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added).
// Add in downlink_mode when ready
// arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 )
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_keep_EM();
T55xx_SendCMD (0, 0, 0, arg); //, true);
TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP);
// Acquisition
DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0);
@ -1251,42 +1462,23 @@ void T55xxResetRead(void) {
}
// Write one card block in page 0, no lock
void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
/*
arg bits
xxxxxxx1 0x01 PwdMode
xxxxxx1x 0x02 Page
xxxxx1xx 0x04 testMode
xxx11xxx 0x18 downlink mode
xx1xxxxx 0x20 !reg_readmode
x1xxxxxx 0x40 called for a read, so no data packet
1xxxxxxx 0x80 reset
*/
bool testMode = ((arg & 0x04) == 0x04);
arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0
LED_A_ON ();
bool PwdMode = arg & 0x1;
uint8_t Page = (arg & 0x2)>>1;
bool testMode = arg & 0x4;
uint32_t i = 0;
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
StartTicks();
// make sure tag is fully powered up...
WaitMS(5);
// Trigger T55x7 in mode.
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(START_GAP);
if (testMode) Dbprintf("TestMODE");
// Std Opcode 10
T55xxWriteBit(testMode ? 0 : 1);
T55xxWriteBit(testMode ? 1 : Page); //Page 0
if (PwdMode) {
// Send Pwd
for (i = 0x80000000; i != 0; i >>= 1)
T55xxWriteBit(Pwd & i);
}
// Send Lock bit
T55xxWriteBit(0);
// Send Data
for (i = 0x80000000; i != 0; i >>= 1)
T55xxWriteBit(Data & i);
// Send Block number
for (i = 0x04; i != 0; i >>= 1)
T55xxWriteBit(Block & i);
T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false);
// Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
// so wait a little more)
@ -1315,57 +1507,43 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg
//DoPartialAcquisition(20, true, 12000);
}
// turn field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
cmd_send(CMD_ACK,0,0,0,0,0);
LED_A_OFF ();
}
// Write one card block in page 0, no lock
void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) {
T55xxWriteBlockExt(Data, Block, Pwd, arg);
cmd_send(CMD_ACK,0,0,0,0,0);
}
// Read one card block in page [page]
void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
LED_A_ON();
bool PwdMode = arg0 & 0x1;
uint8_t Page = (arg0 & 0x2) >> 1;
uint32_t i = 0;
bool RegReadMode = (Block == 0xFF);//regular read mode
void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) {
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_ext(false);
LED_A_ON();
/*
arg bits
xxxxxxx1 0x01 PwdMode
xxxxxx1x 0x02 Page
xxxxx1xx 0x04 testMode
xxx11xxx 0x18 downlink mode
xx1xxxxx 0x20 !reg_readmode
x1xxxxxx 0x40 called for a read, so no data packet
1xxxxxxx 0x80 reset
*/
// Set Read Flag to ensure SendCMD does not add "data" to the packet
arg0 |= 0x40;
// RegRead Mode true of block 0xff
if (Block == 0xff) arg0 |= 0x20;
//make sure block is at max 7
Block &= 0x7;
// Set up FPGA, 125kHz to power up the tag
LFSetupFPGAForADC(95, true);
StartTicks();
// make sure tag is fully powered up...
WaitMS(5);
// Trigger T55x7 Direct Access Mode with start gap
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(START_GAP);
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_ext(false);
// Opcode 1[page]
T55xxWriteBit(1);
T55xxWriteBit(Page); //Page 0
if (PwdMode){
// Send Pwd
for (i = 0x80000000; i != 0; i >>= 1)
T55xxWriteBit(Pwd & i);
}
// Send a zero bit separation
T55xxWriteBit(0);
// Send Block number (if direct access mode)
if (!RegReadMode)
for (i = 0x04; i != 0; i >>= 1)
T55xxWriteBit(Block & i);
T55xx_SendCMD (0, Block, Pwd, arg0); //, true);
// Turn field on to read the response
// 137*8 seems to get to the start of data pretty well...
@ -1379,30 +1557,31 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
// Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
cmd_send(CMD_ACK,0,0,0,0,0);
LED_A_OFF();
}
void T55xxWakeUp(uint32_t Pwd){
LED_B_ON();
uint32_t i = 0;
/*
arg bits
xxxxxxx1 0x01 PwdMode
xxxxxx1x 0x02 Page
xxxxx1xx 0x04 testMode
xxx11xxx 0x18 downlink mode
xx1xxxxx 0x20 !reg_readmode
x1xxxxxx 0x40 called for a read, so no data packet
1xxxxxxx 0x80 reset
*/
// Set up FPGA, 125kHz
LFSetupFPGAForADC(95, true);
StartTicks();
// make sure tag is fully powered up...
WaitMS(5);
// r* 10 (00) <pwd> r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD
// So, default Opcode 10 and pwd.
uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block
// Trigger T55x7 Direct Access Mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
WaitUS(START_GAP);
// Add in downlink_mode when ready
// arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 )
// Opcode 10
T55xxWriteBit(1);
T55xxWriteBit(0); //Page 0
// Send Pwd
for (i = 0x80000000; i != 0; i >>= 1)
T55xxWriteBit(Pwd & i);
T55xx_SendCMD (0, 0, Pwd, arg); //, true);
// Turn and leave field on to let the begin repeating transmission
TurnReadLFOn(20*1000);
@ -1413,12 +1592,13 @@ void T55xxWakeUp(uint32_t Pwd){
void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) {
// write last block first and config block last (if included)
for (uint8_t i = numblocks+startblock; i > startblock; i--) {
T55xxWriteBlockExt(blockdata[i-1],i-1,0,0);
T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit);
//T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit);
}
}
// Copy HID id to card and setup block 0 config
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
// Copy a HID-like card (e.g. HID Proximity, Paradox) to a T55x7 compatible card
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble) {
uint32_t data[] = {0,0,0,0,0,0,0};
uint8_t last_block = 0;
@ -1430,8 +1610,8 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
}
// Build the 6 data blocks for supplied 84bit ID
last_block = 6;
// load preamble (1D) & long format identifier (9E manchester encoded)
data[1] = 0x1D96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF);
// load preamble & long format identifier (9E manchester encoded)
data[1] = (preamble << 24) | 0x96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF);
// load raw id from hi2, hi, lo to data blocks (manchester encoded)
data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF);
data[3] = manchesterEncode2Bytes(hi >> 16);
@ -1447,7 +1627,7 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) {
// Build the 3 data blocks for supplied 44bit ID
last_block = 3;
// load preamble
data[1] = 0x1D000000 | (manchesterEncode2Bytes(hi) & 0xFFFFFF);
data[1] = (preamble << 24) | (manchesterEncode2Bytes(hi) & 0xFFFFFF);
data[2] = manchesterEncode2Bytes(lo >> 16);
data[3] = manchesterEncode2Bytes(lo & 0xFFFF);
}
@ -1613,6 +1793,7 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) {
#define FWD_CMD_WRITE 0xA
#define FWD_CMD_READ 0x9
#define FWD_CMD_DISABLE 0x5
#define FWD_CMD_PROTECT 0x3
uint8_t forwardLink_data[64]; //array of forwarded bits
uint8_t * forward_ptr; //ptr for forward message preparation
@ -1726,7 +1907,7 @@ void SendForward(uint8_t fwd_bit_count) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
WaitUS(18*8); //18 cycles on (8us each)
// now start writting
// now start writting - each bit should be 32*8 total length
while(fwd_bit_sz-- > 0) { //prepare next bit modulation
if(((*fwd_write_ptr++) & 1) == 1)
WaitUS(32*8); //32 cycles at 125Khz (8us each)
@ -1735,7 +1916,7 @@ void SendForward(uint8_t fwd_bit_count) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
WaitUS(23*8); //23 cycles off (8us each)
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on
WaitUS(18*8); //18 cycles on (8us each)
WaitUS((32-23)*8); //remaining cycles on (8us each)
}
}
}
@ -1782,7 +1963,7 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
bool PwdMode = (flag & 0xF);
bool PwdMode = (flag & 0x1);
uint8_t Address = (flag >> 8) & 0xFF;
uint8_t fwd_bit_count;
@ -1812,6 +1993,39 @@ void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
LED_A_OFF();
cmd_send(CMD_ACK,0,0,0,0,0);
}
void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd) {
bool PwdMode = (flag & 0x1);
uint8_t fwd_bit_count;
//clear buffer now so it does not interfere with timing later
BigBuf_Clear_ext(false);
LED_A_ON();
StartTicks();
//If password mode do login
if (PwdMode) EM4xLogin(Pwd);
forward_ptr = forwardLink_data;
fwd_bit_count = Prepare_Cmd( FWD_CMD_PROTECT );
//unsure if this needs the full packet config...
fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 );
SendForward(fwd_bit_count);
//Wait for write to complete
//SpinDelay(10);
WaitUS(6500);
//Capture response if one exists
DoPartialAcquisition(20, true, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_A_OFF();
cmd_send(CMD_ACK,0,0,0,0,0);
}
/*
Reading a COTAG.

View file

@ -12,9 +12,9 @@
#include "string.h"
#include "lfsampling.h"
#include "usb_cdc.h" // for usb_poll_validate_length
//#include "ticks.h" // for StartTicks
#include "fpgaloader.h"
sample_config config = { 1, 8, 1, 95, 0 } ;
sample_config config = { 1, 8, 1, 95, 0, 0 } ;
void printConfig()
{
@ -24,6 +24,7 @@ void printConfig()
Dbprintf(" [d] decimation: %d ", config.decimation);
Dbprintf(" [a] averaging: %d ", config.averaging);
Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold);
Dbprintf(" [s] samples to skip: %d ", config.samples_to_skip);
}
@ -34,16 +35,17 @@ void printConfig()
* 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)
* Values set to '0' implies no change (except for averaging, threshold, samples_to_skip)
* @brief setSamplingConfig
* @param sc
*/
void setSamplingConfig(sample_config *sc)
{
void setSamplingConfig(uint8_t *config_data) {
sample_config *sc = (sample_config *)config_data;
if (sc->divisor != 0) config.divisor = sc->divisor;
if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample;
if (sc->decimation != 0) config.decimation = sc->decimation;
if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold;
if (sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip;
config.averaging= sc->averaging;
if (config.bits_per_sample > 8) config.bits_per_sample = 8;
@ -119,7 +121,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
* @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples.
*/
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after)
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after, int samples_to_skip)
{
//.
uint8_t *dest = BigBuf_get_addr();
@ -141,6 +143,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
uint32_t sample_total_numbers =0 ;
uint32_t sample_total_saved =0 ;
uint32_t cancel_counter = 0;
uint32_t samples_skipped = 0;
while(!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
@ -160,6 +163,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
continue;
}
trigger_threshold = 0;
if (samples_to_skip > samples_skipped) {
samples_skipped++;
continue;
}
sample_total_numbers++;
if(averaging)
@ -218,7 +225,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent)
{
return DoAcquisition(1,8,0,trigger_threshold,silent,0,0);
return DoAcquisition(1,8,0,trigger_threshold,silent,0,0,0);
}
uint32_t DoAcquisition_config(bool silent, int sample_size)
{
@ -228,11 +235,12 @@ uint32_t DoAcquisition_config(bool silent, int sample_size)
,config.trigger_threshold
,silent
,sample_size
,0);
,0
,config.samples_to_skip);
}
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) {
return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after);
return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after,0);
}
uint32_t ReadLF(bool activeField, bool silent, int sample_size)

View file

@ -1,5 +1,5 @@
#ifndef LFSAMPLING_H
#define LFSAMPLING_H
#ifndef LFSAMPLING_H__
#define LFSAMPLING_H__
/**
* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384
@ -61,7 +61,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field);
* @brief setSamplingConfig
* @param sc
*/
void setSamplingConfig(sample_config *sc);
void setSamplingConfig(uint8_t *config_data);
sample_config *getSamplingConfig();

View file

@ -15,32 +15,60 @@
#include "mifarecmd.h"
#include <stdint.h>
#include "proxmark3.h"
#include "usb_cdc.h"
#include "crapto1/crapto1.h"
#include "iso14443a.h"
#include "BigBuf.h"
#include "mifareutil.h"
#include "apps.h"
#include "protocols.h"
#include "util.h"
#include "parity.h"
#include "crc.h"
#include "fpgaloader.h"
#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
/*
// the block number for the ISO14443-4 PCB
static uint8_t pcb_blocknum = 0;
// Deselect card by sending a s-block. the crc is precalced for speed
static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};
static void OnSuccess(){
pcb_blocknum = 0;
ReaderTransmit(deselect_cmd, 3 , NULL);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
*/
static void OnError(uint8_t reason){
// pcb_blocknum = 0;
// ReaderTransmit(deselect_cmd, 3 , NULL);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
cmd_send(CMD_ACK,0,reason,0,0,0);
LED_A_OFF();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
// params
LED_A_ON();
uint8_t blockNo = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
ui64Key = bytes_to_num(datain, 6);
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
uint8_t uid[10];
@ -53,17 +81,13 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
clear_trace();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
@ -87,24 +111,22 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
LED_A_ON();
bool turnOffField = (arg0 == 1);
LED_A_ON(); LED_B_OFF(); LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
@ -119,9 +141,11 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
if (turnOffField) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
LED_D_OFF();
}
cmd_send(CMD_ACK,1,0,0,0,0);
LED_A_OFF();
}
// Arg0 = BlockNo,
@ -129,17 +153,15 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
// datain = PWD bytes,
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
{
LED_A_ON();
uint8_t blockNo = arg0;
byte_t dataout[16] = {0x00};
bool useKey = (arg1 == 1); //UL_C
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
@ -181,9 +203,11 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
return;
}
cmd_send(CMD_ACK,1,0,0,dataout,16);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
LED_D_OFF();
cmd_send(CMD_ACK,1,0,0,dataout,16);
LED_A_OFF();
}
//-----------------------------------------------------------------------------
@ -222,7 +246,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
}
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST, NULL)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
}
@ -244,12 +268,13 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo));
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
@ -259,13 +284,11 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// datain = KEY bytes
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
{
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// free eventually allocated BigBuf memory
BigBuf_free();
clear_trace();
// params
uint8_t blockNo = arg0;
@ -340,14 +363,15 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
return;
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks);
if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks);
countblocks *= 4;
cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
LED_D_OFF();
cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0);
BigBuf_free();
LED_A_OFF();
}
//-----------------------------------------------------------------------------
@ -387,7 +411,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
break;
};
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
@ -411,13 +435,14 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
@ -455,8 +480,9 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
cmd_send(CMD_ACK,1,0,0,0,0);
LEDsoff();
}
*/
@ -524,8 +550,9 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
cmd_send(CMD_ACK,1,0,0,0,0);
LEDsoff();
}
@ -593,8 +620,9 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
return;
};
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
cmd_send(CMD_ACK,1,0,0,0,0);
LEDsoff();
}
@ -612,8 +640,7 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
// Computer and Communications Security, 2015
//-----------------------------------------------------------------------------
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain)
{
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) {
uint64_t ui64Key = 0;
uint8_t uid[10];
uint32_t cuid;
@ -638,7 +665,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
bool field_off = flags & 0x0004;
LED_A_ON();
LED_C_OFF();
if (initialize) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -646,8 +672,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
set_tracing(true);
}
LED_C_ON();
uint16_t num_nonces = 0;
bool have_uid = false;
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) {
@ -685,7 +709,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
}
uint32_t nt1;
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
continue;
}
@ -719,20 +743,18 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
}
LED_C_OFF();
crypto1_destroy(pcs);
LED_B_ON();
cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_B_OFF();
if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished");
if (field_off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
LED_D_OFF();
}
if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished");
cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_A_OFF();
}
@ -740,9 +762,8 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
// MIFARE nested authentication.
//
//-----------------------------------------------------------------------------
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain)
{
// params
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain) {
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
uint8_t targetBlockNo = arg1 & 0xff;
@ -751,14 +772,15 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
ui64Key = bytes_to_num(datain, 6);
// variables
uint16_t rtr, i, j, len;
uint16_t davg;
static uint16_t dmin, dmax;
uint8_t uid[10];
uint32_t cuid, nt1, nt2, nttmp, nttest, ks1;
uint32_t cuid, nt1, nt2_enc, nttmp, nttest, ks1;
uint8_t par[1];
uint32_t target_nt[2], target_ks[2];
uint32_t fixed_nt = 0;
uint8_t target_nt_duplicate_count = 0;
uint8_t par_array[4];
uint16_t ncount = 0;
@ -767,11 +789,10 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
pcs = &mpcs;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint32_t auth1_time, auth2_time;
uint32_t auth1_time, auth2_time, authentication_timeout = 0;
static uint16_t delta_time;
LED_A_ON();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// free eventually allocated BigBuf memory
@ -785,7 +806,6 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
#define NESTED_MAX_TRIES 12
uint16_t unsuccessfull_tries = 0;
if (calibrate) { // for first call only. Otherwise reuse previous calibration
LED_B_ON();
WDT_HIT();
davg = dmax = 0;
@ -794,12 +814,6 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
for (rtr = 0; rtr < 17; rtr++) {
// Test if the action was cancelled
if(BUTTON_PRESS()) {
isOK = -2;
break;
}
// prepare next select. No need to power down the card.
if (mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
@ -807,6 +821,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue;
}
// Test if the action was cancelled
if (BUTTON_PRESS()) {
isOK = -2;
break;
}
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
rtr--;
@ -814,18 +834,19 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
};
auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
rtr--;
continue;
};
fixed_nt = nt1;
if (delta_time) {
auth2_time = auth1_time + delta_time;
} else {
auth2_time = 0;
}
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2_enc, &auth2_time, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");
rtr--;
continue;
@ -834,7 +855,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
for (i = 101; i < 1200; i++) {
nttmp = prng_successor(nttmp, 1);
if (nttmp == nt2) break;
if (nttmp == nt2_enc) break;
}
if (i != 1200) {
@ -862,18 +883,14 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
dmin = davg - 2;
dmax = davg + 2;
LED_B_OFF();
}
// -------------------------------------------------------------------------------------------------
LED_C_ON();
// get crypted nonces for target sector
for (i = 0; i < 2 && !isOK; i++) { // look for exactly two different nonces
target_nt[i] = 0;
while(target_nt[i] == 0) { // continue until we have an unambiguous nonce
while (target_nt[i] == 0 && !isOK) { // continue until we have an unambiguous nonce
// prepare next select. No need to power down the card.
if (mifare_classic_halt(pcs, cuid)) {
@ -881,16 +898,23 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue;
}
// break out of the loop on button press
if (BUTTON_PRESS()) {
isOK = -2;
break;
}
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
continue;
};
}
auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
authentication_timeout = 0;
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time, &authentication_timeout)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
continue;
};
}
// nested authentication
auth2_time = auth1_time + delta_time;
@ -898,10 +922,10 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
if (len != 4) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);
continue;
};
}
nt2 = bytes_to_num(receivedAnswer, 4);
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]);
nt2_enc = bytes_to_num(receivedAnswer, 4);
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2_enc, par[0]);
// Parity validity check
for (j = 0; j < 4; j++) {
@ -912,9 +936,9 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
nttest = prng_successor(nt1, dmin - 1);
for (j = dmin; j < dmax + 1; j++) {
nttest = prng_successor(nttest, 1);
ks1 = nt2 ^ nttest;
ks1 = nt2_enc ^ nttest;
if (valid_nonce(nttest, nt2, ks1, par_array)){
if (valid_nonce(nttest, nt2_enc, ks1, par_array)){
if (ncount > 0) { // we are only interested in disambiguous nonces, try again
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);
target_nt[i] = 0;
@ -924,7 +948,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
target_ks[i] = ks1;
ncount++;
if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces
target_nt[i] = 0;
if( ++target_nt_duplicate_count >= NESTED_MAX_TRIES ) { // unable to get a 2nd nonce after NESTED_MAX_TRIES tries, probably a fixed nonce
if (MF_DBGLEVEL >= 2) Dbprintf("Nonce#2: cannot get nonce that != nonce#1, continuing anyway with single nonce! ntdist=%d", j);
break;
}
target_nt[1] = 0;
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);
break;
}
@ -935,86 +964,148 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
}
}
LED_C_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
byte_t buf[4 + 4 * 4];
uint8_t buf[4 + 4 * 4 + 4 + 4];
memcpy(buf, &cuid, 4);
memcpy(buf+4, &target_nt[0], 4);
memcpy(buf+8, &target_ks[0], 4);
memcpy(buf+12, &target_nt[1], 4);
memcpy(buf+16, &target_ks[1], 4);
LED_B_ON();
cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));
LED_B_OFF();
memcpy(buf+20, &authentication_timeout, 4);
memcpy(buf+24, &fixed_nt, 4);
if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));
LED_A_OFF();
}
//-----------------------------------------------------------------------------
// MIFARE check keys. key count up to 85.
//
//-----------------------------------------------------------------------------
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
{
void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain) {
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
uint8_t keyType = arg0 >> 8;
bool clearTrace = arg1 & 0x01;
bool multisectorCheck = arg1 & 0x02;
uint8_t set14aTimeout = (arg1 >> 8) & 0xff;
bool init = arg1 & 0x04;
bool drop_field = arg1 & 0x08;
bool fixed_nonce = arg1 & 0x10;
uint32_t auth_timeout = arg1 >> 16;
uint8_t keyCount = arg2;
// clear debug level
LED_A_ON();
if (init) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
}
if (clearTrace) {
clear_trace();
}
set_tracing(true);
// clear debug level. We are expecting lots of authentication failures...
int OLD_MF_DBGLEVEL = MF_DBGLEVEL;
MF_DBGLEVEL = MF_DBG_NONE;
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if (clearTrace) clear_trace();
set_tracing(true);
if (set14aTimeout){
iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe
}
int res = 0;
if (multisectorCheck) {
TKeyIndex keyIndex = {{0}};
uint8_t sectorCnt = blockNo;
int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex);
LED_B_ON();
res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, &auth_timeout, OLD_MF_DBGLEVEL, &keyIndex);
if (res >= 0) {
cmd_send(CMD_ACK, 1, 0, 0, keyIndex, 80);
cmd_send(CMD_ACK, 1, res, 0, keyIndex, 80);
} else {
cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
cmd_send(CMD_ACK, 0, res, 0, NULL, 0);
}
LED_B_OFF();
} else {
int res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, OLD_MF_DBGLEVEL);
LED_B_ON();
} else if (fixed_nonce) {
res = MifareChkBlockKeysFixedNonce(datain, keyCount, blockNo, keyType, &auth_timeout, OLD_MF_DBGLEVEL);
if (res > 0) {
cmd_send(CMD_ACK, 1, 0, 0, datain + (res - 1) * 6, 6);
cmd_send(CMD_ACK, 1, res, 0, NULL, 0); // key found
} else {
cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
cmd_send(CMD_ACK, 0, res, 0, NULL, 0); // no key found or aborted
}
} else {
res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, &auth_timeout, OLD_MF_DBGLEVEL);
if (res > 0) {
cmd_send(CMD_ACK, 1, res, 0, datain + (res - 1) * 6, 6);
} else {
cmd_send(CMD_ACK, 0, res, 0, NULL, 0);
}
LED_B_OFF();
}
if (drop_field || res != 0) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
LED_D_OFF();
}
// restore debug level
MF_DBGLEVEL = OLD_MF_DBGLEVEL;
LED_A_OFF();
}
//-----------------------------------------------------------------------------
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
//-----------------------------------------------------------------------------
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *data) {
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
LED_A_ON();
clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
bool isOK = false;
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
}
uint8_t block_number = 0;
uint64_t key = bytes_to_num(data, 6);
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
}
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
break;;
}
isOK = true;
break;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("PERSONALIZE UID FINISHED");
cmd_send(CMD_ACK, isOK, 0, 0, NULL, 0);
LED_A_OFF();
}
//-----------------------------------------------------------------------------
@ -1090,13 +1181,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
ui64Key = emlGetKey(sectorNo, keyType);
if (sectorNo == 0){
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST, NULL)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);
break;
}
} else {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED, NULL)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
break;
@ -1192,13 +1283,13 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// wipe
if (needWipe){
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break;
};
@ -1213,16 +1304,16 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// select commands
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
// gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
if (!gen1b) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
@ -1230,7 +1321,7 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// send blocks command
for (int blockNo = 0; blockNo < numBlocks; blockNo++) {
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break;
};
@ -1248,7 +1339,7 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// send write command
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break;
};
@ -1266,13 +1357,14 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
break;
}
// reset fpga
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// send USB response
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,NULL,0);
LED_B_OFF();
// reset fpga
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
return;
@ -1337,13 +1429,13 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// Wipe command don't work with gen1b
if (needWipe && !(workFlags & 0x40)){
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break;
};
@ -1359,23 +1451,23 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL);
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
// gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
if (!(workFlags & 0x40)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
}
}
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break;
};
@ -1384,7 +1476,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
AppendCrc14443a(d_block, 16);
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break;
};
@ -1404,15 +1496,16 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
break;
}
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,uid,4);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
}
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
@ -1452,14 +1545,14 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
while (true) {
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
// do no issue for gen1b magic tag
if (!(workFlags & 0x40)) {
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
@ -1488,6 +1581,10 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
break;
}
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
LED_B_ON();
if (workFlags & 0x20) {
if (isOK)
@ -1497,11 +1594,8 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
cmd_send(CMD_ACK,isOK,0,0,data,18);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
}
void MifareCIdent(){
@ -1524,11 +1618,11 @@ void MifareCIdent(){
set_tracing(true);
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) {
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
isOK = 2;
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) {
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
isOK = 1;
};
};
@ -1536,11 +1630,12 @@ void MifareCIdent(){
// From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it.
mifare_classic_halt(NULL, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
@ -1571,6 +1666,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED");
cmd_send(CMD_ACK, 1, cuid, 0, dataout, sizeof(dataout));
}
@ -1591,24 +1687,11 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
return;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED");
cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void OnSuccess(){
pcb_blocknum = 0;
ReaderTransmit(deselect_cmd, 3 , NULL);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void OnError(uint8_t reason){
pcb_blocknum = 0;
ReaderTransmit(deselect_cmd, 3 , NULL);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
cmd_send(CMD_ACK,0,reason,0,0,0);
LEDsoff();
}

View file

@ -10,18 +10,36 @@
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
#ifndef __MIFARECMD_H
#define __MIFARECMD_H
#ifndef MIFARECMD_H__
#define MIFARECMD_H__
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include <stdint.h>
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
extern void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
extern void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
//extern void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
extern void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
extern void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
extern void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain);
extern void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
extern void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCIdent(); // is "magic chinese" card?
extern void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
extern void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *datain);
//desfire
extern void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
extern void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
#endif

View file

@ -20,9 +20,10 @@
#include "fpgaloader.h"
#include "proxmark3.h"
#include "usb_cdc.h"
#include "cmd.h"
#include "protocols.h"
#include "apps.h"
#include "util.h"
//mifare emulator states
#define MFEMUL_NOFIELD 0
@ -39,8 +40,6 @@
#define MFEMUL_INTREG_REST 11
#define MFEMUL_HALTED 12
#define cardSTATE_TO_IDLE() { cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); }
#define AC_DATA_READ 0
#define AC_DATA_WRITE 1
#define AC_DATA_INC 2
@ -57,6 +56,25 @@
#define AUTHKEYNONE 0xff
static int ParamCardSizeBlocks(const char c) {
int numBlocks = 16 * 4;
switch (c) {
case '0' : numBlocks = 5 * 4; break;
case '2' : numBlocks = 32 * 4; break;
case '4' : numBlocks = 32 * 4 + 8 * 16; break;
default: numBlocks = 16 * 4;
}
return numBlocks;
}
static uint8_t BlockToSector(int block_num) {
if (block_num < 32 * 4) { // 4 blocks per sector
return (block_num / 4);
} else { // 16 blocks per sector
return 32 + (block_num - 32 * 4) / 16;
}
}
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
uint8_t sector_trailer[16];
emlGetMem(sector_trailer, blockNo, 1);
@ -78,7 +96,7 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act
break;
}
case AC_KEYB_WRITE: {
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04))
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
break;
}
@ -169,14 +187,14 @@ static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
}
static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len) {
static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t cardsize) {
#define TAG_RESPONSE_COUNT 5 // number of precompiled responses
static uint8_t rATQA[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID
static uint8_t rATQA[] = {0x00, 0x00};
static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level
static uint8_t rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated
static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished
static uint8_t rSAKfinal[]= {0x00, 0x00, 0x00}; // SAK after UID complete
static uint8_t rSAK1[] = {0x00, 0x00, 0x00}; // indicate UID not finished
*uid_len = 4;
// UID can be set from emulator memory or incoming data and can be 4 or 7 bytes long
@ -204,17 +222,16 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **
case 4:
*cuid = bytes_to_num(rUIDBCC1, 4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
if (MF_DBGLEVEL >= 2) {
if (MF_DBGLEVEL >= MF_DBG_INFO) {
Dbprintf("4B UID: %02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] );
}
break;
case 7:
rATQA[0] |= 0x40;
*cuid = bytes_to_num(rUIDBCC2, 4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
if (MF_DBGLEVEL >= 2) {
if (MF_DBGLEVEL >= MF_DBG_INFO) {
Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x",
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3] );
}
@ -223,6 +240,35 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **
break;
}
// set SAK based on cardsize
switch (cardsize) {
case '0': rSAKfinal[0] = 0x09; break; // Mifare Mini
case '2': rSAKfinal[0] = 0x10; break; // Mifare 2K
case '4': rSAKfinal[0] = 0x18; break; // Mifare 4K
default: rSAKfinal[0] = 0x08; // Mifare 1K
}
ComputeCrc14443(CRC_14443_A, rSAKfinal, 1, rSAKfinal + 1, rSAKfinal + 2);
if (MF_DBGLEVEL >= MF_DBG_INFO) {
Dbprintf("SAK: %02x", rSAKfinal[0]);
}
// set SAK for incomplete UID
rSAK1[0] = 0x04; // Bit 3 indicates incomplete UID
ComputeCrc14443(CRC_14443_A, rSAK1, 1, rSAK1 + 1, rSAK1 + 2);
// set ATQA based on cardsize and UIDlen
if (cardsize == '4') {
rATQA[0] = 0x02;
} else {
rATQA[0] = 0x04;
}
if (*uid_len == 7) {
rATQA[0] |= 0x40;
}
if (MF_DBGLEVEL >= MF_DBG_INFO) {
Dbprintf("ATQA: %02x %02x", rATQA[1], rATQA[0]);
}
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
{ .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
@ -232,7 +278,7 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **
};
// Prepare ("precompile") the responses of the anticollision phase. There will be not enough time to do this at the moment the reader sends its REQA or SELECT
// There are 7 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// There are 5 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 18 * 8 data bits, 18 * 1 parity bits, 5 start bits, 5 stop bits, 5 correction bits -> need 177 bytes buffer
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses
@ -262,20 +308,21 @@ static bool HasValidCRC(uint8_t *receivedCmd, uint16_t receivedCmd_len) {
/**
*MIFARE 1K simulate.
*MIFARE simulate.
*
*@param flags :
* FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK
* FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that
* FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that
* FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished
* FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later
* FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack)
*@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ...
* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted)
*/
void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain)
void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain)
{
LED_A_ON();
tag_response_info_t *responses;
uint8_t uid_len = 4;
uint32_t cuid = 0;
@ -288,8 +335,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
uint32_t cardINTREG = 0;
uint8_t cardINTBLOCK = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
struct Crypto1State *pcs = &mpcs;
uint32_t numReads = 0; //Counts numer of times reader reads a block
uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE];
@ -297,11 +343,11 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
uint16_t receivedCmd_len;
uint8_t response[MAX_MIFARE_FRAME_SIZE];
uint8_t response_par[MAX_MIFARE_PARITY_SIZE];
uint8_t fixed_nonce[] = {0x01, 0x02, 0x03, 0x04};
uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
int num_blocks = ParamCardSizeBlocks(cardsize);
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
// Here we collect UID, sector, keytype, NT, AR, NR, NT2, AR2, NR2
// This will be used in the reader-only attack.
// allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys
@ -322,13 +368,13 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
if (flags & FLAG_RANDOM_NONCE) {
nonce = prand();
} else {
nonce = bytes_to_num(rAUTH_NT, 4);
nonce = bytes_to_num(fixed_nonce, 4);
}
// free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM();
MifareSimInit(flags, datain, &responses, &cuid, &uid_len);
MifareSimInit(flags, datain, &responses, &cuid, &uid_len, cardsize);
// We need to listen to the high-frequency, peak-detected path.
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
@ -345,25 +391,28 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
while (!button_pushed && !finished && !usb_poll_validate_length()) {
WDT_HIT();
// find reader field
if (cardSTATE == MFEMUL_NOFIELD) {
// wait for reader HF field
int vHf = (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10;
if (vHf > MF_MINFIELDV) {
LED_A_ON();
cardSTATE_TO_IDLE();
LED_D_ON();
cardSTATE = MFEMUL_IDLE;
}
button_pushed = BUTTON_PRESS();
continue;
}
//Now, get data
FpgaEnableTracing();
int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par);
if (res == 2) { //Field is off!
LEDsoff();
if (res == 2) { // Reader has dropped the HF field. Power off.
FpgaDisableTracing();
LED_D_OFF();
cardSTATE = MFEMUL_NOFIELD;
continue;
} else if (res == 1) { // button pressed
FpgaDisableTracing();
button_pushed = true;
break;
}
@ -371,6 +420,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// WUPA in HALTED state or REQA or WUPA in any other state
if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) {
EmSendPrecompiledCmd(&responses[ATQA]);
FpgaDisableTracing();
// init crypto block
crypto1_destroy(pcs);
@ -378,8 +428,6 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
if (flags & FLAG_RANDOM_NONCE) {
nonce = prand();
}
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_SELECT1;
continue;
}
@ -390,52 +438,56 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
case MFEMUL_IDLE:{
break;
}
case MFEMUL_SELECT1:{
// select all - 0x93 0x20
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL1 received");
EmSendPrecompiledCmd(&responses[UIDBCC1]);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL1 received");
break;
}
// select card - 0x93 0x70 ...
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC1].response, 4) == 0)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
if (uid_len == 4) {
EmSendPrecompiledCmd(&responses[SAKfinal]);
LED_B_ON();
cardSTATE = MFEMUL_WORK;
break;
} else if (uid_len == 7) {
EmSendPrecompiledCmd(&responses[SAK1]);
cardSTATE = MFEMUL_SELECT2;
}
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
break;
}
}
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
case MFEMUL_SELECT2:{
// select all cl2 - 0x95 0x20
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL2 received");
EmSendPrecompiledCmd(&responses[UIDBCC2]);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL2 received");
break;
}
// select cl2 card - 0x95 0x70 xxxxxxxxxxxx
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) {
if (uid_len == 7) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
EmSendPrecompiledCmd(&responses[SAKfinal]);
LED_B_ON();
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
cardSTATE = MFEMUL_WORK;
break;
}
}
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
case MFEMUL_WORK:{
if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes
break;
@ -448,59 +500,71 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len);
}
if (!HasValidCRC(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_TR));
break;
}
if (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB) {
// if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack
if (receivedCmd_dec[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) {
if (receivedCmd_dec[1] >= num_blocks && !(flags & FLAG_NR_AR_ATTACK)) {
//is this the correct response to an auth on a out of range block? marshmellow
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]);
break;
}
cardAUTHSC = receivedCmd_dec[1] / 4; // received block num
cardAUTHSC = BlockToSector(receivedCmd_dec[1]); // received block num
cardAUTHKEY = receivedCmd_dec[0] & 0x01;
crypto1_destroy(pcs);//Added by martin
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
if (!encrypted_data) { // first authentication
if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
crypto1_word(pcs, cuid ^ nonce, 0); // Update crypto state
num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce
num_to_bytes(nonce, 4, response); // Send unencrypted nonce
EmSendCmd(response, sizeof(nonce));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
} else { // nested authentication
if (MF_DBGLEVEL >= 4) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(ans, 4, rAUTH_AT);
num_to_bytes(nonce, sizeof(nonce), response);
uint8_t pcs_in[4] = {0};
num_to_bytes(cuid ^ nonce, sizeof(nonce), pcs_in);
mf_crypto1_encryptEx(pcs, response, pcs_in, sizeof(nonce), response_par);
EmSendCmdPar(response, sizeof(nonce), response_par); // send encrypted nonce
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
}
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
cardSTATE = MFEMUL_AUTH1;
break;
}
if (!encrypted_data) { // all other commands must be encrypted (authenticated)
// halt can be sent encrypted or in clear
if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("--> HALTED.");
cardSTATE = MFEMUL_HALTED;
break;
}
if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK
|| receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK
if(receivedCmd_dec[0] == MIFARE_CMD_READBLOCK
|| receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK
|| receivedCmd_dec[0] == MIFARE_CMD_INC
|| receivedCmd_dec[0] == MIFARE_CMD_DEC
|| receivedCmd_dec[0] == MIFARE_CMD_RESTORE
|| receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) {
if (receivedCmd_dec[1] >= 16 * 4) {
if (receivedCmd_dec[1] >= num_blocks) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
break;
}
if (receivedCmd_dec[1] / 4 != cardAUTHSC) {
if (BlockToSector(receivedCmd_dec[1]) != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC);
break;
}
}
if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) {
if (receivedCmd_dec[0] == MIFARE_CMD_READBLOCK) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) {
Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo);
}
emlGetMem(response, blockNo, 1);
if (IsSectorTrailer(blockNo)) {
memset(response, 0x00, 6); // keyA can never be read
@ -518,6 +582,10 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
AppendCrc14443a(response, 16);
mf_crypto1_encrypt(pcs, response, 18, response_par);
EmSendCmdPar(response, 18, response_par);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo);
}
numReads++;
if(exitAfterNReads > 0 && numReads == exitAfterNReads) {
Dbprintf("%d reads done, exiting", numReads);
@ -525,23 +593,33 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
break;
}
if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) {
if (receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo);
cardWRBL = blockNo;
cardSTATE = MFEMUL_WRITEBL2;
break;
}
if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
if (emlCheckValBl(blockNo)) {
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
break;
}
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) {
Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
}
cardWRBL = blockNo;
if (receivedCmd_dec[0] == MIFARE_CMD_INC)
cardSTATE = MFEMUL_INTREG_INC;
@ -551,31 +629,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
cardSTATE = MFEMUL_INTREG_REST;
break;
}
if (receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1]))
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
else
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
break;
}
// halt
if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) {
if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED.");
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_HALTED;
break;
}
// command not allowed
if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Received command not allowed, nacking");
cardSTATE = MFEMUL_IDLE;
break;
}
case MFEMUL_AUTH1:{
if (receivedCmd_len != 8) {
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
@ -650,7 +726,8 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B',
cardRr, prng_successor(nonce, 64));
// Shouldn't we respond anything here?
@ -658,17 +735,19 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
// reader to do a WUPA after a while. /Martin
// -- which is the correct response. /piwi
cardAUTHKEY = AUTHKEYNONE; // not authenticated
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
num_to_bytes(ans, 4, rAUTH_AT);
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B');
LED_C_ON();
ans = prng_successor(nonce, 96);
num_to_bytes(ans, 4, response);
mf_crypto1_encrypt(pcs, response, 4, response_par);
EmSendCmdPar(response, 4, response_par);
FpgaDisableTracing();
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B');
cardSTATE = MFEMUL_WORK;
break;
}
case MFEMUL_WRITEBL2:{
if (receivedCmd_len == 18) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec);
@ -695,53 +774,60 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
break;
}
}
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
case MFEMUL_INTREG_INC:{
if (receivedCmd_len == 6) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
cardINTREG = cardINTREG + ans;
}
cardSTATE = MFEMUL_WORK;
}
break;
}
case MFEMUL_INTREG_DEC:{
if (receivedCmd_len == 6) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
}
cardINTREG = cardINTREG - ans;
cardSTATE = MFEMUL_WORK;
}
break;
}
case MFEMUL_INTREG_REST:{
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
cardSTATE = MFEMUL_IDLE;
break;
}
cardSTATE = MFEMUL_WORK;
break;
}
}
} // end of switch
FpgaDisableTracing();
button_pushed = BUTTON_PRESS();
}
} // end of while
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) {
if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= MF_DBG_INFO) {
for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
@ -758,7 +844,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
for ( uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT*2; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
Dbprintf("../tools/mfkey/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x",
Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x %08x",
ar_nr_resp[i].cuid, //UID
ar_nr_resp[i].nonce, //NT
ar_nr_resp[i].nr, //NR1
@ -770,10 +856,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *
}
}
}
if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen());
if (MF_DBGLEVEL >= MF_DBG_INFO) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen());
if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK
//Send the collected ar_nr in the response
cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp));
}
LED_A_OFF();
}

View file

@ -15,6 +15,6 @@
#include <stdint.h>
extern void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain);
extern void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain);
#endif

View file

@ -9,7 +9,7 @@
//-----------------------------------------------------------------------------
#include "mifaresniff.h"
#include "apps.h"
#include "proxmark3.h"
#include "util.h"
#include "string.h"
@ -18,6 +18,9 @@
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "usb_cdc.h"
#include "BigBuf.h"
#include "fpgaloader.h"
static int sniffState = SNF_INIT;
@ -149,7 +152,7 @@ bool intMfSniffSend() {
while (pckLen > 0) {
pckSize = MIN(USB_CMD_DATA_SIZE, pckLen);
LED_B_ON();
cmd_send(CMD_ACK, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize);
cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize);
LED_B_OFF();
pckLen -= pckSize;
@ -157,7 +160,7 @@ bool intMfSniffSend() {
}
LED_B_ON();
cmd_send(CMD_ACK,2,0,0,0,0);
cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,2,0,0,0,0);
LED_B_OFF();
clear_trace();

View file

@ -21,9 +21,10 @@
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "polarssl/des.h"
#include "mbedtls/des.h"
#include "protocols.h"
int MF_DBGLEVEL = MF_DBG_ALL;
int MF_DBGLEVEL = MF_DBG_INFO;
// crypto1 helpers
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){
@ -47,14 +48,14 @@ 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) {
void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par) {
uint8_t bt = 0;
int i;
par[0] = 0;
for (i = 0; i < len; i++) {
bt = data[i];
data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i];
data[i] = crypto1_byte(pcs, in==NULL?0x00:in[i], 0) ^ data[i];
if((i&0x0007) == 0)
par[i>>3] = 0;
par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007)));
@ -62,6 +63,10 @@ void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, u
return;
}
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) {
mf_crypto1_encryptEx(pcs, data, NULL, len, par);
}
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
uint8_t bt = 0;
int i;
@ -73,8 +78,7 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
}
// 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)
{
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);
@ -90,8 +94,7 @@ int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answe
}
// 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)
{
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) {
uint8_t dcmd[4], ecmd[4];
uint16_t pos, res;
uint8_t par[1]; // 1 Byte parity is enough here
@ -108,9 +111,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd,
ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos];
par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos));
}
ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing);
} else {
ReaderTransmit(dcmd, sizeof(dcmd), timing);
}
@ -138,18 +139,18 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd,
return len;
}
// mifare classic commands
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested)
{
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *auth_timeout) {
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL, auth_timeout);
}
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)
{
// 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, uint32_t *auth_timeout) {
int len;
uint32_t pos;
uint8_t tmp4[4];
uint8_t par[1] = {0x00};
byte_t nr[4];
uint32_t nt, ntpp; // Supplied tag nonce
@ -159,7 +160,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// Transmit MIFARE_CLASSIC_AUTH
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing);
len = mifare_sendcmd_short(pcs, isNested, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len);
if (len != 4) return 1;
@ -197,8 +198,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
// Generate (encrypted) nr+parity by loading it into the cipher (Nr)
par[0] = 0;
for (pos = 0; pos < 4; pos++)
{
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));
}
@ -207,8 +207,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
nt = prng_successor(nt,32);
// ar+parity
for (pos = 4; pos < 8; pos++)
{
for (pos = 4; pos < 8; pos++) {
nt = prng_successor(nt,8);
mf_nr_ar[pos] = crypto1_byte(pcs, 0x00, 0) ^ (nt & 0xff);
par[0] |= (((filter(pcs->odd) ^ oddparity8(nt)) & 0x01) << (7-pos));
@ -218,17 +217,24 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL);
// Receive 4 byte tag answer
uint32_t save_timeout = iso14a_get_timeout(); // save standard timeout
if (auth_timeout && *auth_timeout) {
iso14a_set_timeout(*auth_timeout); // set timeout for authentication response
}
uint32_t auth_timeout_start = GetCountSspClk();
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
if (!len)
{
iso14a_set_timeout(save_timeout); // restore standard timeout
if (!len) {
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout.");
return 2;
}
if (auth_timeout && !*auth_timeout) { // measure time for future authentication response timeout
*auth_timeout = (GetCountSspClk() - auth_timeout_start - (len * 9 + 2) * 8) / 8 + 1;
}
memcpy(tmp4, receivedAnswer, 4);
ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
if (ntpp != bytes_to_num(tmp4, 4)) {
if (ntpp != bytes_to_num(receivedAnswer, 4)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response.");
return 3;
}
@ -236,8 +242,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
return 0;
}
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData)
{
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
// variables
int len;
uint8_t bt[2];
@ -246,7 +252,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
@ -278,7 +284,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){
if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]);
len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL);
len = mifare_sendcmd(MIFARE_ULEV1_AUTH, key, sizeof(key), resp, respPar, NULL);
//len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
if (len != 4) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len);
@ -296,7 +302,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
/// 3des2k
des3_context ctx = { 0x00 };
mbedtls_des3_context ctx = { {0} };
uint8_t random_a[8] = {1,1,1,1,1,1,1,1};
uint8_t random_b[8] = {0x00};
uint8_t enc_random_b[8] = {0x00};
@ -310,7 +316,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
uint8_t respPar[3] = {0,0,0};
// REQUEST AUTHENTICATION
len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, resp, respPar ,NULL);
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;
@ -321,9 +327,9 @@ int mifare_ultra_auth(uint8_t *keybytes){
// decrypt nonce.
// tdes_2key_dec(random_b, enc_random_b, sizeof(random_b), key, IV );
des3_set2key_dec(&ctx, key);
des3_crypt_cbc(&ctx // des3_context
, DES_DECRYPT // int mode
mbedtls_des3_set2key_dec(&ctx, key);
mbedtls_des3_crypt_cbc(&ctx // des3_context
, MBEDTLS_DES_DECRYPT // int mode
, sizeof(random_b) // length
, IV // iv[8]
, enc_random_b // input
@ -350,9 +356,9 @@ int mifare_ultra_auth(uint8_t *keybytes){
// encrypt out, in, length, key, iv
//tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b);
des3_set2key_enc(&ctx, key);
des3_crypt_cbc(&ctx // des3_context
, DES_ENCRYPT // int mode
mbedtls_des3_set2key_enc(&ctx, key);
mbedtls_des3_crypt_cbc(&ctx // des3_context
, MBEDTLS_DES_ENCRYPT // int mode
, sizeof(rnd_ab) // length
, enc_random_b // iv[8]
, rnd_ab // input
@ -360,7 +366,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
);
//len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
if (len != 11) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
return 0;
@ -372,9 +378,9 @@ int mifare_ultra_auth(uint8_t *keybytes){
// decrypt out, in, length, key, iv
// tdes_2key_dec(resp_random_a, enc_resp, 8, key, enc_random_b);
des3_set2key_dec(&ctx, key);
des3_crypt_cbc(&ctx // des3_context
, DES_DECRYPT // int mode
mbedtls_des3_set2key_dec(&ctx, key);
mbedtls_des3_crypt_cbc(&ctx // des3_context
, MBEDTLS_DES_DECRYPT // int mode
, 8 // length
, enc_random_b // iv[8]
, enc_resp // input
@ -417,7 +423,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
int result = 0;
for (retries = 0; retries < MFU_MAX_RETRIES; retries++) {
len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(NULL, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
result = 1;
@ -447,7 +453,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
return result;
}
memcpy(blockData, receivedAnswer, 14);
memcpy(blockData, receivedAnswer, 16);
return 0;
}
@ -464,7 +470,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// command MIFARE_CLASSIC_WRITEBLOCK
len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
@ -507,7 +513,7 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData)
uint8_t receivedAnswer[MAX_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(NULL, true, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= MF_DBG_ERROR)
@ -559,7 +565,7 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid)
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
if (len != 0) {
if (MF_DBGLEVEL >= MF_DBG_ERROR)
Dbprintf("halt error. response len: %x", len);
@ -575,7 +581,7 @@ int mifare_ultra_halt()
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL);
len = mifare_sendcmd_short(NULL, true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
if (len != 0) {
if (MF_DBGLEVEL >= MF_DBG_ERROR)
Dbprintf("halt error. response len: %x", len);
@ -806,18 +812,17 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
//
//-----------------------------------------------------------------------------
// one key check
int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint64_t ui64Key, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
static int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint8_t *key, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, bool fixed_nonce) {
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// Iceman: use piwi's faster nonce collecting part in hardnested.
if (*cascade_levels == 0) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, cuid, true, 0, true)) {
if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card");
return 1;
return -1;
}
switch (card_info.uidlen) {
case 4 : *cascade_levels = 1; break;
@ -828,75 +833,90 @@ int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uin
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) {
if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels);
return 1;
return -1;
}
}
if(mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout()
return 2;
if (!fixed_nonce) {
uint64_t ui64Key = bytes_to_num(key, 6);
if (mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST, auth_timeout)) { // authentication failed
return -2;
} else {
/* // let it be here. it like halt command, but maybe it will work in some strange cases
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
// wait for the card to become ready again
while(GetCountSspClk() < timeout) {};
*/
// it needs after success authentication
mifare_classic_halt(pcs, *cuid);
}
} else {
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// Transmit MIFARE_CLASSIC_AUTH
int len = mifare_sendcmd_short(pcs, false, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len != 4) return -2;
// Transmit encrypted reader nonce and reader answer
uint8_t mf_nr_ar[8] = NESTED_FIXED_NR_ENC;
memcpy(mf_nr_ar + 4, key, 4);
ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), key + 4, NULL);
uint32_t save_timeout = iso14a_get_timeout(); // save standard timeout
iso14a_set_timeout(*auth_timeout); // set timeout for authentication response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
iso14a_set_timeout(save_timeout); // restore standard timeout
if (!len) return -2;
}
return 0;
return 0; // success
}
// multi key check
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
static int MifareChkBlockKeysEx(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, bool fixed_nonce) {
uint8_t uid[10];
uint32_t cuid = 0;
uint8_t cascade_levels = 0;
uint64_t ui64Key = 0;
int retryCount = 0;
for (uint8_t i = 0; i < keyCount; i++) {
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !usb_poll_validate_length()) {
Dbprintf("ChkKeys: Cancel operation. Exit...");
return -2;
}
ui64Key = bytes_to_num(keys + i * 6, 6);
int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, debugLevel);
// can't select
if (res == 1) {
uint8_t bytes_per_key = fixed_nonce ? 5 : 6;
int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, keys + i*bytes_per_key, blockNo, keyType, auth_timeout, debugLevel, fixed_nonce);
if (res == -1) { // couldn't select
retryCount++;
if (retryCount >= 5) {
Dbprintf("ChkKeys: block=%d key=%d. Can't select. Exit...", blockNo, keyType);
Dbprintf("ChkKeys: block=%d key=%d. Couldn't select. Exit...", blockNo, keyType);
return -1;
}
} else {
--i; // try the same key once again
SpinDelay(20);
// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType);
continue;
}
// can't authenticate
if (res == 2) {
}
if (res == -2) { // couldn't authenticate with this key
retryCount = 0;
continue; // can't auth. wrong key.
continue;
}
return i + 1;
return i + 1; // successful authentication
}
return 0;
if (BUTTON_PRESS()) {
return -2;
}
return 0; // couldn't authenticate with any key
}
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel) {
return MifareChkBlockKeysEx(keys, keyCount, blockNo, keyType, auth_timeout, debugLevel, false);
}
// fixed nonce check
int MifareChkBlockKeysFixedNonce(uint8_t *ar_par, uint8_t ar_par_cnt, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel) {
return MifareChkBlockKeysEx(ar_par, ar_par_cnt, blockNo, keyType, auth_timeout, debugLevel, true);
}
// multisector multikey check
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex) {
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, TKeyIndex *keyIndex) {
int res = 0;
// int clk = GetCountSspClk();
@ -906,7 +926,7 @@ int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, u
int keyAB = keyType;
do {
res = MifareChkBlockKeys(keys, keyCount, FirstBlockOfSector(sc), keyAB & 0x01, debugLevel);
res = MifareChkBlockKeys(keys, keyCount, FirstBlockOfSector(sc), keyAB & 0x01, auth_timeout, debugLevel);
if (res < 0) {
return res;
}
@ -918,7 +938,7 @@ int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, u
// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1)));
return 0;
return 1;
}

View file

@ -9,8 +9,8 @@
// code for work with mifare cards.
//-----------------------------------------------------------------------------
#ifndef __MIFAREUTIL_H
#define __MIFAREUTIL_H
#ifndef MIFAREUTIL_H__
#define MIFAREUTIL_H__
#include <stdint.h>
#include <stdbool.h>
@ -25,20 +25,15 @@
#define AUTH_FIRST 0
#define AUTH_NESTED 2
// mifare 4bit card answers
#define CARD_ACK 0x0A // 1010 - ACK
#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed)
#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error
// reader voltage field detector
#define MF_MINFIELDV 4000
// debug
// 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
#define MF_DBG_NONE 0 // no messages
#define MF_DBG_ERROR 1 // errors only
#define MF_DBG_INFO 2 // errors + info messages
#define MF_DBG_DEBUG 3 // errors + info + debug messages
#define MF_DBG_EXTENDED 4 // errors + info + debug + breaking debug messages
extern int MF_DBGLEVEL;
@ -47,8 +42,8 @@ int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answe
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
// mifare classic
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing);
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *auth_timeout);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing, uint32_t *auth_timeout);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
@ -71,6 +66,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out);
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par);
void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par);
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data);
// Mifare memory structure
@ -91,8 +87,8 @@ int emlCheckValBl(int blockNum);
// mifare check keys
typedef uint8_t TKeyIndex[2][40];
int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint64_t ui64Key, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel);
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel);
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex);
int MifareChkBlockKeysFixedNonce(uint8_t *ar_par, uint8_t ar_par_cnt, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel);
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel);
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, TKeyIndex *keyIndex);
#endif

View file

@ -60,15 +60,63 @@
-- MHS 2015
**/
/**
The runtime of opt_doTagMAC_2() with the MHS optimized version was 403 microseconds on Proxmark3.
This was still to slow for some newer readers which didn't want to wait that long.
Further optimizations to speedup the MAC calculations:
* Optimized opt_Tt logic
* Look up table for opt_select
* Removing many unnecessary bit maskings (& 0x1)
* updating state in place instead of alternating use of a second state structure
* remove the necessity to reverse bits of input and output bytes
opt_doTagMAC_2() now completes in 270 microseconds.
-- piwi 2019
**/
#include "optimized_cipher.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "string.h"
static const uint8_t opt_select_LUT[256] = {
00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04,
01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04,
06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06,
07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06,
06, 05, 04, 07, 04, 05, 06, 07, 02, 01, 01, 02, 00, 01, 03, 02,
03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06,
00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00,
05, 06, 07, 04, 06, 07, 04, 05, 05, 06, 06, 05, 06, 07, 05, 04,
02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06,
03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06,
02, 01, 00, 03, 00, 01, 02, 03, 02, 01, 01, 02, 00, 01, 03, 02,
03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02,
04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00,
01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04,
04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04,
01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00
};
#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)
/********************** the table above has been generated with this code: ********
#include "util.h"
static void init_opt_select_LUT(void) {
for (int r = 0; r < 256; r++) {
uint8_t r_ls2 = r << 2;
uint8_t r_and_ls2 = r & r_ls2;
uint8_t r_or_ls2 = r | r_ls2;
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r;
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r;
opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1);
}
print_result("", opt_select_LUT, 256);
}
***********************************************************************************/
#define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\
|(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\
@ -78,9 +126,6 @@
* 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
@ -100,94 +145,95 @@ uint8_t xopt__select(bool x, bool y, uint8_t r)
}
*/
void opt_successor(const uint8_t* k, State *s, bool y, State* successor)
{
static void opt_successor(const uint8_t *k, State *s, uint8_t y) {
// #define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14) ^ (s->t >> 10) ^ (s->t >> 8) ^ (s->t >> 5) ^ (s->t >> 4)^ (s->t >> 1) ^ s->t))
// uint8_t Tt = opt_T(s);
uint16_t Tt = s->t & 0xc533;
Tt = Tt ^ (Tt >> 1);
Tt = Tt ^ (Tt >> 4);
Tt = Tt ^ (Tt >> 10);
Tt = Tt ^ (Tt >> 8);
uint8_t Tt = 1 & opt_T(s);
s->t = (s->t >> 1);
s->t |= (Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15;
successor->t = (s->t >> 1);
successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15;
uint8_t opt_B = s->b;
opt_B ^= s->b >> 6;
opt_B ^= s->b >> 5;
opt_B ^= s->b >> 4;
successor->b = s->b >> 1;
successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7;
s->b = s->b >> 1;
s->b |= (opt_B ^ s->r) << 7;
successor->r = (k[opt__select(Tt,y,s->r)] ^ successor->b) + s->l ;
successor->l = successor->r+s->r;
uint8_t opt_select = opt_select_LUT[s->r] & 0x04;
opt_select |= (opt_select_LUT[s->r] ^ ((Tt ^ y) << 1)) & 0x02;
opt_select |= (opt_select_LUT[s->r] ^ Tt) & 0x01;
uint8_t r = s->r;
s->r = (k[opt_select] ^ s->b) + s->l ;
s->l = s->r + r;
}
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);
static void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) {
for (int i = 0; i < length; i++) {
uint8_t head;
head = in[i];
opt_successor(k, s, head);
head = 1 & (in[i] >> 6);
opt_successor(k,&x2,head,s);
head >>= 1;
opt_successor(k, s, head);
head = 1 & (in[i] >> 5);
opt_successor(k,s,head,&x2);
head >>= 1;
opt_successor(k, s, head);
head = 1 & (in[i] >> 4);
opt_successor(k,&x2,head,s);
head >>= 1;
opt_successor(k, s, head);
head = 1 & (in[i] >> 3);
opt_successor(k,s,head,&x2);
head >>= 1;
opt_successor(k, s, head);
head = 1 & (in[i] >> 2);
opt_successor(k,&x2,head,s);
head >>= 1;
opt_successor(k, s, head);
head = 1 & (in[i] >> 1);
opt_successor(k,s,head,&x2);
head = 1 & in[i];
opt_successor(k,&x2,head,s);
head >>= 1;
opt_successor(k, s, head);
head >>= 1;
opt_successor(k, s, head);
}
//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);
if (add32Zeroes) {
for(int i = 0; i < 16; i++) {
opt_successor(k, s, 0);
opt_successor(k, s, 0);
}
}
}
void opt_output(const uint8_t* k,State* s, uint8_t *buffer)
{
uint8_t times = 0;
static void opt_output(const uint8_t *k, State *s, uint8_t *buffer) {
for (uint8_t times = 0; times < 4; times++) {
uint8_t bout = 0;
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) >> 2;
opt_successor(k, s, 0);
bout |= (s->r & 0x4) >> 1;
opt_successor(k,s,0,&temp);
bout |= (temp.r & 0x4) >> 2;
opt_successor(k,&temp,0,s);
opt_successor(k, s, 0);
bout |= (s->r & 0x4);
opt_successor(k, s, 0);
bout |= (s->r & 0x4) << 1;
opt_successor(k, s, 0);
bout |= (s->r & 0x4) << 2;
opt_successor(k, s, 0);
bout |= (s->r & 0x4) << 3;
opt_successor(k, s, 0);
bout |= (s->r & 0x4) << 4;
opt_successor(k, s, 0);
bout |= (s->r & 0x4) << 5;
opt_successor(k, s, 0);
buffer[times] = bout;
}
}
void opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out)
{
static void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) {
State _init = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
@ -199,48 +245,26 @@ void opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out)
//printf("\noutp ");
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);
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) {
uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0};
opt_MAC(div_key_p,cc_nr, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
opt_MAC(div_key_p, cc_nr_p, dest);
memcpy(mac, dest, 4);
return;
}
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4])
{
static uint8_t cc_nr[8+4+4];
opt_reverse_arraybytecpy(cc_nr, cc_p,12);
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) {
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p,&_init,cc_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);
opt_suc(div_key_p, &_init, cc_p, 12, true);
opt_output(div_key_p, &_init, mac);
return;
}
/**
* The tag MAC can be divided (both can, but no point in dividing the reader mac) into
* two functions, since the first 8 bytes are known, we can pre-calculate the state
@ -249,19 +273,17 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4])
* @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 opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) {
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p,&_init,cc_nr, 8,false);
opt_suc(div_key_p, &_init, cc_p, 8, false);
return _init;
}
/**
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
* this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag
@ -271,15 +293,8 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p)
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p)
{
static uint8_t _nr [4];
opt_reverse_arraybytecpy(_nr, nr, 4);
opt_suc(div_key_p,&_init,_nr, 4, true);
//opt_suc(div_key_p,&_init,nr, 4, false);
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);
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) {
opt_suc(div_key_p, &_init, nr, 4, true);
opt_output(div_key_p, &_init, mac);
return;
}

View file

@ -35,8 +35,9 @@
*
****************************************************************************/
#ifndef OPTIMIZED_CIPHER_H
#define OPTIMIZED_CIPHER_H
#ifndef OPTIMIZED_CIPHER_H__
#define OPTIMIZED_CIPHER_H__
#include <stdint.h>
/**
@ -57,6 +58,7 @@ typedef struct {
/** 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))
*/
@ -71,6 +73,7 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]);
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
/**
* 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
@ -82,4 +85,4 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
*/
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p);
#endif // OPTIMIZED_CIPHER_H
#endif // OPTIMIZED_CIPHER_H__

View file

@ -1,15 +1,16 @@
#include "proxmark3.h"
#include "apps.h"
#include "usb_cdc.h"
#include "lfsampling.h"
#include "pcf7931.h"
#include "util.h"
#include "string.h"
#include "fpgaloader.h"
#define T0_PCF 8 //period for the pcf7931 in us
#define ALLOC 16
int DemodPCF7931(uint8_t **outBlocks) {
size_t DemodPCF7931(uint8_t **outBlocks) {
uint8_t bits[256] = {0x00};
uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr();
@ -18,13 +19,12 @@ int DemodPCF7931(uint8_t **outBlocks) {
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;
size_t num_blocks = 0;
int lmin=128, lmax=128;
uint8_t dir;
//clear read buffer
@ -46,8 +46,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
i++;
}
dir = 0;
}
else {
} else {
while(i < GraphTraceLen) {
if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
break;
@ -61,10 +60,8 @@ int DemodPCF7931(uint8_t **outBlocks) {
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))
{
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;
@ -78,8 +75,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
lastval = i;
pmc = 0;
block_done = 1;
}
else {
} else {
pmc = i;
}
} else if (ABS(lc-clock/2) < tolerance) {
@ -90,8 +86,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
lastval = i;
pmc = 0;
block_done = 1;
}
else if(half_switch == 1) {
} else if(half_switch == 1) {
bits[bitidx++] = 0;
half_switch = 0;
}
@ -102,9 +97,7 @@ int DemodPCF7931(uint8_t **outBlocks) {
bits[bitidx++] = 1;
} else {
// Error
warnings++;
if (warnings > 10)
{
if (++warnings > 10) {
Dbprintf("Error: too many detection errors, aborting.");
return 0;
}
@ -112,16 +105,17 @@ int DemodPCF7931(uint8_t **outBlocks) {
if(block_done == 1) {
if(bitidx == 128) {
for(j=0; j<16; j++) {
blocks[num_blocks][j] = 128*bits[j*8+7]+
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];
bits[j*8]
;
}
num_blocks++;
}
@ -141,184 +135,223 @@ int DemodPCF7931(uint8_t **outBlocks) {
return num_blocks;
}
int IsBlock0PCF7931(uint8_t *Block) {
// Assume RFU means 0 :)
if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled
return 1;
if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ?
return 1;
return 0;
bool IsBlock0PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0
// if PAC is enabled password is set to 0
if (block[7] == 0x01)
{
if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7))
return true;
}
else if (block[7] == 0x00)
{
if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7))
return true;
}
return false;
}
int IsBlock1PCF7931(uint8_t *Block) {
// Assume RFU means 0 :)
if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0)
if((Block[14] & 0x7f) <= 9 && Block[15] <= 9)
return 1;
bool IsBlock1PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0
return 0;
uint8_t rb1 = block[14] & 0x80;
uint8_t rfb = block[14] & 0x7f;
uint8_t rlb = block[15];
if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
// block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled
if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1))
return true;
return false;
}
void ReadPCF7931() {
uint8_t Blocks[8][17];
uint8_t tmpBlocks[4][16];
int i, j, ind, ind2, n;
int num_blocks = 0;
int max_blocks = 8;
int ident = 0;
int error = 0;
int tries = 0;
int found_blocks = 0; // successfully read blocks
int max_blocks = 8; // readable blocks
uint8_t memory_blocks[8][17]; // PCF content
memset(Blocks, 0, 8*17*sizeof(uint8_t));
uint8_t single_blocks[8][17]; // PFC blocks with unknown position
int single_blocks_cnt = 0;
size_t n = 0; // transmitted blocks
uint8_t tmp_blocks[4][16]; // temporary read buffer
uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
int errors = 0; // error counter
int tries = 0; // tries counter
memset(memory_blocks, 0, 8*17*sizeof(uint8_t));
memset(single_blocks, 0, 8*17*sizeof(uint8_t));
int i = 0, j = 0;
do {
memset(tmpBlocks, 0, 4*16*sizeof(uint8_t));
n = DemodPCF7931((uint8_t**)tmpBlocks);
i = 0;
memset(tmp_blocks, 0, 4*16*sizeof(uint8_t));
n = DemodPCF7931((uint8_t**)tmp_blocks);
if(!n)
error++;
if(error==10 && num_blocks == 0) {
++errors;
// exit if no block is received
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
Dbprintf("Error, no tag or bad tag");
return;
}
else if (tries==20 || error==10) {
// exit if too many errors during reading
if (tries > 50 && (2*errors > tries)) {
Dbprintf("Error reading the tag");
Dbprintf("Here is the partial content");
goto end;
}
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;
}
// our logic breaks if we don't get at least two blocks
if (n < 2) {
// skip if all 0s block or no blocks
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
continue;
// add block to single blocks list
if (single_blocks_cnt < max_blocks) {
for (i = 0; i < single_blocks_cnt; ++i) {
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
j = 1;
break;
}
}
if (j != 1) {
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
print_result("got single block", single_blocks[single_blocks_cnt], 16);
single_blocks_cnt++;
}
j = 0;
}
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;
++tries;
continue;
}
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
for (i = 0; i < n; ++i)
{
print_result("got consecutive blocks", tmp_blocks[i], 16);
}
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;
i = 0;
if(!found_0_1) {
while (i < n - 1) {
if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) {
found_0_1 = 1;
memcpy(memory_blocks[0], tmp_blocks[i], 16);
memcpy(memory_blocks[1], tmp_blocks[i+1], 16);
memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
// block 1 tells how many blocks are going to be sent
max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
found_blocks = 2;
Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
// handle the following blocks
for (j = i + 2; j < n; ++j) {
memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
memory_blocks[found_blocks][ALLOC] = 1;
++found_blocks;
}
break;
}
++i;
}
} else {
// Trying to re-order blocks
// Look for identical block in memory blocks
while (i < n-1) {
// skip all zeroes blocks
if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
for (j = 1; j < max_blocks - 1; ++j) {
if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) {
memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16);
memory_blocks[j+1][ALLOC] = 1;
if (++found_blocks >= max_blocks) goto end;
}
}
}
if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
for (j = 0; j < max_blocks; ++j) {
if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) {
if (j == 0) {
memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16);
memory_blocks[max_blocks - 1][ALLOC] = 1;
} else {
memcpy(memory_blocks[j-1], tmp_blocks[i], 16);
memory_blocks[j-1][ALLOC] = 1;
}
if (++found_blocks >= max_blocks) goto end;
}
}
}
++i;
}
tries++;
if (BUTTON_PRESS()) return;
} while (num_blocks != max_blocks);
}
++tries;
if (BUTTON_PRESS()) {
Dbprintf("Button pressed, stopping.");
goto end;
}
}
while (found_blocks < max_blocks);
end:
Dbprintf("-----------------------------------------");
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for(i=0; i<max_blocks; i++) {
if(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]);
for (i = 0; i < max_blocks; ++i) {
if (memory_blocks[i][ALLOC])
print_result("Block", memory_blocks[i], 16);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
if (found_blocks < max_blocks) {
Dbprintf("-----------------------------------------");
Dbprintf("Blocks with unknown position:");
Dbprintf("-----------------------------------------");
for (i = 0; i < single_blocks_cnt; ++i)
print_result("Block", single_blocks[i], 16);
Dbprintf("-----------------------------------------");
}
cmd_send(CMD_ACK,0,0,0,0,0);
}
/* 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)
{
static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
uint32_t tab[1024]={0}; // data times frame
uint32_t u = 0;
uint8_t parity = 0;
bool comp = 0;
//BUILD OF THE DATA FRAME
//alimentation of the tag (time for initializing)
AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab);
//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);
AddBytePCF7931(pass[0], tab, l, p);
AddBytePCF7931(pass[1], tab, l, p);
AddBytePCF7931(pass[2], tab, l, p);
AddBytePCF7931(pass[3], tab, l, p);
AddBytePCF7931(pass[4], tab, l, p);
AddBytePCF7931(pass[5], tab, l, p);
AddBytePCF7931(pass[6], tab, l, p);
//programming mode (0 or 1)
AddBitPCF7931(0, tab, l, p);
//block adress on 6 bits
Dbprintf("Block address : %02x", address);
for (u=0; u<6; u++)
{
for (u = 0; u < 6; ++u) {
if (address & (1 << u)) { // bit 1
parity++;
++parity;
AddBitPCF7931(1, tab, l, p);
} else { // bit 0
AddBitPCF7931(0, tab, l, p);
@ -326,60 +359,108 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui
}
//byte address on 4 bits
Dbprintf("Byte address : %02x", byte);
for (u=0; u<4; u++)
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);
}
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
}
else //bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//parity bit
if((parity%2)==0){
if ((parity % 2) == 0)
AddBitPCF7931(0, tab, l, p); //even parity
}else{
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++){
for (u = 0; u < 500; ++u)
tab[u] = (tab[u] * 3) / 2;
}
//compennsation of the counter reload
while (!comp) {
comp = 1;
for(u=0;tab[u]!=0;u++){
for (u = 0; tab[u] != 0; ++u)
if(tab[u] > 0xFFFF) {
tab[u] -= 0xFFFF;
comp = 0;
}
}
}
SendCmdPCF7931(tab);
}
void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p) {
uint8_t i = 0;
uint8_t pass_array[7];
while (password < 0x00FFFFFFFFFFFFFF) {
if (BUTTON_PRESS()) {
Dbprintf("Button pressed, stopping bruteforce ...");
return;
}
num_to_bytes(password, 7, pass_array);
Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...",
pass_array[0],
pass_array[1],
pass_array[2],
pass_array[3],
pass_array[4],
pass_array[5],
pass_array[6]);
for (i = 0; i < tries; ++i)
RealWritePCF7931
(
pass_array,
init_delay,
l,
p,
0,
7,
0x01
);
++password;
}
}
/* Write on a byte of a PCF7931 tag
* @param address : address of the block to write
@param byte : address of the byte to write
@param data : data to write
*/
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
Dbprintf("Initialization delay : %d us", init_delay);
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
Dbprintf("Block address : %02x", address);
Dbprintf("Byte address : %02x", byte);
Dbprintf("Data : %02x", data);
uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
RealWritePCF7931 (password, init_delay, l, p, address, byte, data);
}
/* Send a trame to a PCF7931 tags
@ -390,12 +471,10 @@ void SendCmdPCF7931(uint32_t * tab){
uint16_t u=0;
uint16_t tempo=0;
Dbprintf("SENDING DATA FRAME...");
Dbprintf("Sending data frame ...");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
LED_A_ON();
@ -412,41 +491,30 @@ void SendCmdPCF7931(uint32_t * tab){
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]){
while(tempo != tab[u])
tempo = AT91C_BASE_TC0->TC_CV;
}
// stop modulating antenna
LOW(GPIO_SSC_DOUT);
while(tempo != tab[u+1]){
while(tempo != tab[u+1])
tempo = AT91C_BASE_TC0->TC_CV;
}
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while(tempo != tab[u+2]){
while(tempo != tab[u+2])
tempo = AT91C_BASE_TC0->TC_CV;
}
}
LED_A_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
DbpString("FINISH !");
DbpString("(Could be usefull to send the same trame many times)");
DbpString("Data frame sent (multiple sends may be needed)");
LED(0xFFFF, 1000);
}
@ -457,15 +525,12 @@ void SendCmdPCF7931(uint32_t * tab){
* @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
for (u = 0; u < 8; ++u) {
if (byte & (1 << u)) { //bit is 1
if(AddBitPCF7931(1, tab, l, p)==1)return 1;
} else { //bit à 0
} else { //bit is 0
if(AddBitPCF7931(0, tab, l, p)==1)return 1;
}
}
@ -484,7 +549,6 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array
if (b == 1) { //add a bit 1
if (u == 0) tab[u] = 34 * T0_PCF + p;
else tab[u] = 34 * T0_PCF + tab[u-1] + p;
@ -502,7 +566,6 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
return 0;
}
return 1;
}

View file

@ -1,14 +1,15 @@
#ifndef __PCF7931_H
#define __PCF7931_H
int DemodPCF7931(uint8_t **outBlocks);
int IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block);
size_t DemodPCF7931(uint8_t **outBlocks);
bool IsBlock0PCF7931(uint8_t *Block);
bool IsBlock1PCF7931(uint8_t *Block);
void ReadPCF7931();
void SendCmdPCF7931(uint32_t * tab);
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);
bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p);
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab);
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data);
void BruteForcePCF7931(uint64_t start_password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p);
#endif

View file

@ -11,8 +11,7 @@
#include "string.h"
#include <stdint.h>
void *memcpy(void *dest, const void *src, int len)
{
void *memcpy(void *dest, const void *src, size_t len) {
uint8_t *d = dest;
const uint8_t *s = src;
while((len--) > 0) {
@ -23,8 +22,8 @@ void *memcpy(void *dest, const void *src, int len)
return dest;
}
void *memset(void *dest, int c, int len)
{
void *memset(void *dest, int c, size_t len) {
uint8_t *d = dest;
while((len--) > 0) {
*d = c;
@ -33,8 +32,30 @@ void *memset(void *dest, int c, int len)
return dest;
}
int memcmp(const void *av, const void *bv, int len)
{
void *memmove(void *dest, const void *src, size_t len) {
uint8_t *d = dest;
const uint8_t *s = src;
if (dest <= src) {
while((len--) > 0) {
*d = *s;
d++;
s++;
}
} else {
d = d + len - 1;
s = s + len - 1;
while((len--) > 0) {
*d = *s;
d--;
s--;
}
}
return dest;
}
int memcmp(const void *av, const void *bv, size_t len) {
const uint8_t *a = av;
const uint8_t *b = bv;
@ -48,13 +69,8 @@ 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)
{
size_t strlen(const char *str) {
int l = 0;
while(*str) {
l++;
@ -63,8 +79,8 @@ int strlen(const char *str)
return l;
}
char* strncat(char *dest, const char *src, unsigned int n)
{
char* strncat(char *dest, const char *src, size_t n) {
unsigned int dest_len = strlen(dest);
unsigned int i;
@ -75,8 +91,8 @@ char* strncat(char *dest, const char *src, unsigned int n)
return dest;
}
char* strcat(char *dest, const char *src)
{
char* strcat(char *dest, const char *src) {
unsigned int dest_len = strlen(dest);
unsigned int i;
@ -86,35 +102,3 @@ char* strcat(char *dest, const char *src)
return dest;
}
////////////////////////////////////////// code to do 'itoa'
/* reverse: reverse string s in place */
void strreverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
strreverse(s);
}
//////////////////////////////////////// END 'itoa' CODE

View file

@ -12,18 +12,14 @@
#ifndef __STRING_H
#define __STRING_H
#include <stdint.h>
#include "util.h"
#include <stddef.h>
int strlen(const char *str);
RAMFUNC void *memcpy(void *dest, const void *src, int len);
void *memset(void *dest, int c, 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);
void *memcpy(void *dest, const void *src, size_t len);
void *memset(void *dest, int c, size_t len);
void *memmove(void *dest, const void *src, size_t len);
int memcmp(const void *av, const void *bv, size_t len);
size_t strlen(const char *str);
char *strncat(char *dest, const char *src, size_t n);
char *strcat(char *dest, const char *src);
void strreverse(char s[]);
void itoa(int n, char s[]);
#endif /* __STRING_H */

View file

@ -89,6 +89,22 @@ void LEDsoff()
LED_D_OFF();
}
void LEDson()
{
LED_A_ON();
LED_B_ON();
LED_C_ON();
LED_D_ON();
}
void LEDsinvert()
{
LED_A_INV();
LED_B_INV();
LED_C_INV();
LED_D_INV();
}
// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8]
void LED(int led, int ms)
{
@ -121,8 +137,7 @@ void LED(int led, int ms)
// not clicked, or held down (for ms || 1sec)
// In general, don't use this function unless you expect a
// double click, otherwise it will waste 500ms -- use BUTTON_HELD instead
int BUTTON_CLICKED(int ms)
{
int BUTTON_CLICKED(int ms) {
// Up to 500ms in between clicks to mean a double click
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
@ -184,8 +199,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;
@ -202,8 +216,7 @@ int BUTTON_HELD(int ms)
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
for(;;)
{
for(;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// As soon as our button let go, we didn't hold long enough
@ -211,8 +224,7 @@ int BUTTON_HELD(int ms)
return BUTTON_SINGLE_CLICK;
// Have we waited the full second?
else
if (now == (uint16_t)(start + ticks))
else if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
WDT_HIT();
@ -224,8 +236,7 @@ int BUTTON_HELD(int ms)
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayUs(int us)
{
void SpinDelayUs(int us) {
int ticks = (48*us) >> 10;
// Borrow a PWM unit for my real-time clock
@ -246,8 +257,7 @@ void SpinDelayUs(int us)
}
}
void SpinDelay(int ms)
{
void SpinDelay(int ms) {
// convert to uS and call microsecond delay function
SpinDelayUs(ms*1000);
}
@ -298,8 +308,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
// ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
void StartTickCount()
{
void StartTickCount() {
// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency
@ -312,7 +321,7 @@ void StartTickCount()
/*
* Get the current count.
*/
uint32_t RAMFUNC GetTickCount(){
uint32_t RAMFUNC GetTickCount(void) {
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
}
@ -320,8 +329,7 @@ uint32_t RAMFUNC GetTickCount(){
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS()
{
void StartCountUS(void) {
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;
@ -343,14 +351,14 @@ void StartCountUS()
}
uint32_t RAMFUNC GetCountUS(){
uint32_t RAMFUNC GetCountUS(void) {
return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10);
}
static uint32_t GlobalUsCounter = 0;
uint32_t RAMFUNC GetDeltaCountUS(){
uint32_t RAMFUNC GetDeltaCountUS(void) {
uint32_t g_cnt = GetCountUS();
uint32_t g_res = g_cnt - GlobalUsCounter;
GlobalUsCounter = g_cnt;
@ -361,8 +369,7 @@ uint32_t RAMFUNC GetDeltaCountUS(){
// -------------------------------------------------------------------------
// Timer for iso14443 commands. Uses ssp_clk from FPGA
// -------------------------------------------------------------------------
void StartCountSspClk()
{
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
@ -373,13 +380,13 @@ void StartCountSspClk()
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_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04
AT91C_BASE_TC1->TC_RC = 1; // RC Compare value = 1; pulse width to TC0
// use TC0 to count TIOA1 pulses
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
@ -402,18 +409,29 @@ void StartCountSspClk()
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2
//
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14443 mode, otherwise SSC_FRAME and SSC_CLK signals would not be present
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present
//
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
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame
if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame
}
// 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).
// at the next (3rd/7th) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
// at the next (4th/8th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
// whenever the last three/four bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before
// we can use the counter.
while (AT91C_BASE_TC0->TC_CV < 0xFFFF);
@ -429,18 +447,16 @@ void ResetSspClk(void) {
while (AT91C_BASE_TC2->TC_CV > 0);
}
uint32_t GetCountSspClk(){
uint32_t hi, lo;
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;
}
}
do {
hi = AT91C_BASE_TC2->TC_CV;
lo = AT91C_BASE_TC0->TC_CV;
} while (hi != AT91C_BASE_TC2->TC_CV);
return (hi << 16) | lo;
}
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer

View file

@ -8,12 +8,13 @@
// Utility functions used in many places, not specific to any piece of code.
//-----------------------------------------------------------------------------
#ifndef __UTIL_H
#define __UTIL_H
#ifndef UTIL_H__
#define UTIL_H__
#include <stddef.h>
#include <stdint.h>
#include "common.h"
#include "at91sam7s512.h"
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
@ -21,44 +22,52 @@
#define LED_ORANGE 2
#define LED_GREEN 4
#define LED_RED2 8
#define BUTTON_HOLD 1
#define BUTTON_NO_CLICK 0
#define BUTTON_SINGLE_CLICK -1
#define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len);
void lsl (uint8_t *data, size_t len);
#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7))
#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8))
#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16))
#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32))
void LED(int led, int ms);
void LEDsoff();
int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms);
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
extern void print_result(char *name, uint8_t *buf, size_t len);
extern size_t nbytes(size_t nbits);
extern uint32_t SwapBits(uint32_t value, int nrbits);
extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
extern uint64_t bytes_to_num(uint8_t* src, size_t len);
extern void rol(uint8_t *data, const size_t len);
extern void lsl (uint8_t *data, size_t len);
extern void LED(int led, int ms);
extern void LEDsoff();
extern void LEDson();
extern void LEDsinvert();
extern int BUTTON_CLICKED(int ms);
extern int BUTTON_HELD(int ms);
extern void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
//iceman's ticks.h
#ifndef GET_TICKS
# define GET_TICKS GetTicks()
#endif
void SpinDelay(int ms);
void SpinDelayUs(int us);
extern void SpinDelay(int ms);
extern void SpinDelayUs(int us);
void StartTickCount();
uint32_t RAMFUNC GetTickCount();
extern void StartTickCount();
extern uint32_t RAMFUNC GetTickCount();
void StartCountUS();
uint32_t RAMFUNC GetCountUS();
uint32_t RAMFUNC GetDeltaCountUS();
extern void StartCountUS();
extern uint32_t RAMFUNC GetCountUS();
extern uint32_t RAMFUNC GetDeltaCountUS();
void StartCountSspClk();
void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
extern void StartCountSspClk();
extern void ResetSspClk(void);
extern uint32_t GetCountSspClk();
extern void StartTicks(void);
extern uint32_t GetTicks(void);
@ -70,6 +79,6 @@ extern void ResetTimer(AT91PS_TC timer);
extern void StopTicks(void);
// end iceman's ticks.h
uint32_t prand();
extern uint32_t prand();
#endif

View file

@ -7,8 +7,8 @@
#-----------------------------------------------------------------------------
# DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code
ARMSRC =
THUMBSRC = cmd.c usb_cdc.c bootrom.c
ARMSRC = string.c
THUMBSRC = usb_cdc.c bootrom.c
ASMSRC = ram-reset.s flash-reset.s
VERSIONSRC = version.c
@ -19,7 +19,6 @@ VERSIONSRC = version.c
# ARMSRC := $(ARMSRC) $(THUMBSRC)
# THUMBSRC :=
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I.
# version.c should be remade on every compilation

View file

@ -6,17 +6,15 @@
// Main code for the bootloader
//-----------------------------------------------------------------------------
#include <proxmark3.h>
#include "proxmark3.h"
#include "usb_cdc.h"
#include "cmd.h"
//#include "usb_hid.h"
void DbpString(char *str) {
byte_t len = 0;
uint8_t len = 0;
while (str[len] != 0x00) {
len++;
}
cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len);
cmd_send_old(CMD_DEBUG_PRINT_STRING,len,0,0,(uint8_t*)str,len);
}
struct common_area common_area __attribute__((section(".commonarea")));
@ -89,26 +87,22 @@ static void Fatal(void)
for(;;);
}
void UsbPacketReceived(uint8_t *packet, int len) {
void UsbPacketReceived(UsbCommand *c) {
int i, dont_ack=0;
UsbCommand* c = (UsbCommand *)packet;
volatile uint32_t *p;
if(len != sizeof(UsbCommand)) {
Fatal();
}
uint32_t arg0 = (uint32_t)c->arg[0];
switch(c->cmd) {
case CMD_DEVICE_INFO: {
dont_ack = 1;
arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM |
DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH;
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);
cmd_send_old(CMD_DEVICE_INFO,arg0,1,2,0,0);
} break;
case CMD_SETUP_WRITE: {
@ -134,7 +128,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
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);
cmd_send_old(CMD_NACK,0,0,0,0,0);
} else {
uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE;
/* Translate address to flash page and do flash, update here for the 512k part */
@ -148,7 +142,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
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,0,0,0,0,0);
cmd_send_old(CMD_NACK,0,0,0,0,0);
}
}
} break;
@ -179,7 +173,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
} else {
start_addr = end_addr = 0;
dont_ack = 1;
cmd_send(CMD_NACK,0,0,0,0,0);
cmd_send_old(CMD_NACK,0,0,0,0,0);
}
}
} break;
@ -190,7 +184,7 @@ void UsbPacketReceived(uint8_t *packet, int len) {
}
if(!dont_ack) {
cmd_send(CMD_ACK,arg0,0,0,0,0);
cmd_send_old(CMD_ACK,arg0,0,0,0,0);
}
}
@ -199,8 +193,7 @@ 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;
UsbCommand rx;
usb_enable();
for (volatile size_t i=0; i<0x100000; i++) {};
@ -208,11 +201,8 @@ static void flash_mode(int externally_entered)
for(;;) {
WDT_HIT();
if (usb_poll()) {
rx_len = usb_read(rx,sizeof(UsbCommand));
if (rx_len) {
UsbPacketReceived(rx,rx_len);
}
if (cmd_receive(&rx)) {
UsbPacketReceived(&rx);
}
if(!externally_entered && !BUTTON_PRESS()) {

104
bootrom/string.c Normal file
View file

@ -0,0 +1,104 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Sept 2005
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Common string.h functions
//-----------------------------------------------------------------------------
#include "string.h"
#include <stdint.h>
void *memcpy(void *dest, const void *src, size_t len) {
uint8_t *d = dest;
const uint8_t *s = src;
while((len--) > 0) {
*d = *s;
d++;
s++;
}
return dest;
}
void *memset(void *dest, int c, size_t len) {
uint8_t *d = dest;
while((len--) > 0) {
*d = c;
d++;
}
return dest;
}
void *memmove(void *dest, const void *src, size_t len) {
uint8_t *d = dest;
const uint8_t *s = src;
if (dest <= src) {
while((len--) > 0) {
*d = *s;
d++;
s++;
}
} else {
d = d + len - 1;
s = s + len - 1;
while((len--) > 0) {
*d = *s;
d--;
s--;
}
}
return dest;
}
int memcmp(const void *av, const void *bv, size_t len) {
const uint8_t *a = av;
const uint8_t *b = bv;
while((len--) > 0) {
if(*a != *b) {
return *a - *b;
}
a++;
b++;
}
return 0;
}
size_t strlen(const char *str) {
int l = 0;
while(*str) {
l++;
str++;
}
return l;
}
char* strncat(char *dest, const char *src, size_t n) {
unsigned int dest_len = strlen(dest);
unsigned int i;
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}
char* strcat(char *dest, const char *src) {
unsigned int dest_len = strlen(dest);
unsigned int i;
for (i = 0 ; src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}

25
bootrom/string.h Normal file
View file

@ -0,0 +1,25 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, Aug 2005
// 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.
//-----------------------------------------------------------------------------
// Common string.h functions
//-----------------------------------------------------------------------------
#ifndef __STRING_H
#define __STRING_H
#include <stddef.h>
void *memcpy(void *dest, const void *src, size_t len);
void *memset(void *dest, int c, size_t len);
void *memmove(void *dest, const void *src, size_t len);
int memcmp(const void *av, const void *bv, size_t len);
size_t strlen(const char *str);
char *strncat(char *dest, const char *src, size_t n);
char *strcat(char *dest, const char *src);
#endif /* __STRING_H */

View file

@ -21,21 +21,41 @@ LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
LUALIB = ../liblua/liblua.a
JANSSONLIBPATH = ./jansson
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
MBEDTLSLIBPATH = ../common/mbedtls
MBEDTLSLIB = $(MBEDTLSLIBPATH)/libmbedtls.a
CBORLIBPATH = ./tinycbor
CBORLIB = $(CBORLIBPATH)/tinycbor.a
LIBINCLUDES = -I../zlib -I../uart -I../liblua -I$(MBEDTLSLIBPATH) -I$(JANSSONLIBPATH) -I$(CBORLIBPATH)
INCLUDES_CLIENT = -I. -I../include -I../common -I/opt/local/include $(LIBINCLUDES)
LDFLAGS = $(ENV_LDFLAGS)
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -Wall -g -O3
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE $(INCLUDES_CLIENT) -Wall -g -O3
CXXFLAGS = -I../include -Wall -O3
APP_CFLAGS =
include ../common/Makefile_Enabled_Options.common
CFLAGS += $(APP_CFLAGS)
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
SRC_SMARTCARD = cmdsmartcard.c
SRC_SMARTCARD = cmdsmartcard.c pcsc.c
else
SRC_SMARTCARD =
endif
LUAPLATFORM = generic
platform = $(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
PCSC_INCLUDES :=
PCSC_LIBS = -lwinscard
else
ifeq ($(platform),Darwin)
PCSC_INCLUDES =
PCSC_LIBS = -framework PCSC
else
PCSC_INCLUDES := $(shell pkg-config --cflags libpcsclite)
PCSC_LIBS := $(shell pkg-config --libs libpcsclite)
endif
endif
LUAPLATFORM = generic
ifneq (,$(findstring MINGW,$(platform)))
LUAPLATFORM = mingw
else
@ -105,21 +125,26 @@ CORESRCS = uart_posix.c \
CMDSRCS = $(SRC_SMARTCARD) \
crapto1/crapto1.c\
crapto1/crypto1.c\
polarssl/des.c \
polarssl/aes.c\
polarssl/bignum.c\
polarssl/rsa.c\
polarssl/sha1.c\
crypto/libpcrypto.c\
crypto/asn1utils.c\
crypto/asn1dump.c\
cliparser/argtable3.c\
cliparser/cliparser.c\
mfkey.c\
fido/additional_ca.c \
fido/cose.c \
fido/cbortools.c \
fido/fidocore.c \
mifare/mfkey.c \
loclass/cipher.c \
loclass/cipherutils.c \
loclass/ikeys.c \
loclass/elite_crack.c\
loclass/fileutils.c\
whereami.c\
mifarehost.c\
mifare/mifarehost.c\
mifare/mifare4.c\
mifare/mad.c \
mifare/ndef.c \
parity.c\
crc.c \
crc16.c \
@ -140,12 +165,14 @@ CMDSRCS = $(SRC_SMARTCARD) \
emv/tlv.c\
emv/emv_tags.c\
emv/dol.c\
emv/emvjson.c\
emv/emvcore.c\
emv/test/crypto_test.c\
emv/test/sda_test.c\
emv/test/dda_test.c\
emv/test/cda_test.c\
emv/cmdemv.c\
emv/emv_roca.c \
cmdhf.c \
cmdhflist.c \
cmdhf14a.c \
@ -155,10 +182,12 @@ CMDSRCS = $(SRC_SMARTCARD) \
cmdhflegic.c \
cmdhficlass.c \
cmdhfmf.c \
cmdhfmfp.c \
cmdhfmfu.c \
cmdhfmfhard.c \
hardnested/hardnested_bruteforce.c \
cmdhftopaz.c \
cmdhffido.c \
cmdhw.c \
cmdlf.c \
cmdlfawid.c \
@ -191,7 +220,8 @@ CMDSRCS = $(SRC_SMARTCARD) \
cmdscript.c\
pm3_binlib.c\
pm3_bitlib.c\
protocols.c
protocols.c\
taginfo.c
cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), )
@ -238,15 +268,15 @@ endif
BINS = proxmark3 flasher fpga_compress
WINBINS = $(patsubst %, %.exe, $(BINS))
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua
# need to assign dependancies to build these first...
all: lua_build jansson_build $(BINS)
all: lua_build jansson_build mbedtls_build cbor_build $(BINS)
all-static: LDLIBS:=-static $(LDLIBS)
all-static: proxmark3 flasher fpga_compress
proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(QTLDLIBS)
proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) $(PCSC_LIBS)
proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua
$(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@
@ -270,7 +300,9 @@ lualibs/usb_cmd.lua: ../include/usb_cmd.h
clean:
$(RM) $(CLEAN)
cd ../liblua && make clean
cd ./jansson && make clean
cd $(JANSSONLIBPATH) && make clean
cd $(MBEDTLSLIBPATH) && make clean
cd $(CBORLIBPATH) && make clean
tarbin: $(BINS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
@ -281,7 +313,15 @@ lua_build:
jansson_build:
@echo Compiling jansson
cd ./jansson && make all
cd $(JANSSONLIBPATH) && make all
mbedtls_build:
@echo Compiling mbedtls
cd $(MBEDTLSLIBPATH) && make all
cbor_build:
@echo Compiling tinycbor
cd $(CBORLIBPATH) && make all
.PHONY: all clean
@ -305,7 +345,7 @@ $(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d
%.o: %.c
$(OBJDIR)/%.o : %.c $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $<
$(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) $(PCSC_INCLUDES) -c -o $@ $<
$(POSTCOMPILE)
%.o: %.cpp

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,6 @@
/*******************************************************************************
* argtable3: Declares the main interfaces of the library
*
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
@ -39,20 +41,39 @@ extern "C" {
#endif
#define ARG_REX_ICASE 1
#define ARG_DSTR_SIZE 200
#define ARG_CMD_NAME_LEN 100
#define ARG_CMD_DESCRIPTION_LEN 256
#ifndef ARG_REPLACE_GETOPT
#define ARG_REPLACE_GETOPT 1 /* use the embedded getopt as the system getopt(3) */
#endif /* ARG_REPLACE_GETOPT */
/* bit masks for arg_hdr.flag */
enum
{
ARG_TERMINATOR=0x1,
ARG_HASVALUE=0x2,
ARG_HASOPTVALUE=0x4
};
enum { ARG_TERMINATOR = 0x1, ARG_HASVALUE = 0x2, ARG_HASOPTVALUE = 0x4 };
#if defined(_WIN32)
#if defined(argtable3_EXPORTS)
#define ARG_EXTERN __declspec(dllexport)
#elif defined(argtable3_IMPORTS)
#define ARG_EXTERN __declspec(dllimport)
#else
#define ARG_EXTERN
#endif
#else
#define ARG_EXTERN
#endif
typedef struct _internal_arg_dstr* arg_dstr_t;
typedef void* arg_cmd_itr_t;
typedef void(arg_resetfn)(void* parent);
typedef int(arg_scanfn)(void* parent, const char* argval);
typedef int(arg_checkfn)(void* parent);
typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname);
typedef void(arg_errorfn)(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname);
typedef void(arg_dstr_freefn)(char* buf);
typedef int(arg_cmdfn)(int argc, char* argv[], arg_dstr_t res);
typedef int(arg_comparefn)(const void* k1, const void* k2);
/*
* The arg_hdr struct defines properties that are common to all arg_xxx structs.
@ -71,8 +92,7 @@ typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval
* if desired, but the original intention is for them to be set by the
* constructor and left unaltered.
*/
struct arg_hdr
{
typedef struct arg_hdr {
char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */
const char* shortopts; /* String defining the short options */
const char* longopts; /* String defiing the long options */
@ -86,161 +106,94 @@ struct arg_hdr
arg_checkfn* checkfn; /* Pointer to parent arg_xxx check function */
arg_errorfn* errorfn; /* Pointer to parent arg_xxx error function */
void* priv; /* Pointer to private header data for use by arg_xxx functions */
};
} arg_hdr_t;
struct arg_rem
{
typedef struct arg_rem {
struct arg_hdr hdr; /* The mandatory argtable header struct */
};
} arg_rem_t;
struct arg_lit
{
typedef struct arg_lit {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
};
} arg_lit_t;
struct arg_int
{
typedef struct arg_int {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
int* ival; /* Array of parsed argument values */
};
} arg_int_t;
struct arg_dbl
{
typedef struct arg_dbl {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
double* dval; /* Array of parsed argument values */
};
} arg_dbl_t;
struct arg_str
{
typedef struct arg_str {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
const char** sval; /* Array of parsed argument values */
};
} arg_str_t;
struct arg_rex
{
typedef struct arg_rex {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
const char** sval; /* Array of parsed argument values */
};
} arg_rex_t;
struct arg_file
{
typedef struct arg_file {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args*/
const char** filename; /* Array of parsed filenames (eg: /home/foo.bar) */
const char** basename; /* Array of parsed basenames (eg: foo.bar) */
const char** extension; /* Array of parsed extensions (eg: .bar) */
};
} arg_file_t;
struct arg_date
{
typedef struct arg_date {
struct arg_hdr hdr; /* The mandatory argtable header struct */
const char* format; /* strptime format string used to parse the date */
int count; /* Number of matching command line args */
struct tm* tmval; /* Array of parsed time values */
};
} arg_date_t;
enum { ARG_ELIMIT = 1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG };
struct arg_end
{
typedef struct arg_end {
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of errors encountered */
int* error; /* Array of error codes */
void** parent; /* Array of pointers to offending arg_xxx struct */
const char** argval; /* Array of pointers to offending argv[] string */
};
} arg_end_t;
typedef struct arg_cmd_info {
char name[ARG_CMD_NAME_LEN];
char description[ARG_CMD_DESCRIPTION_LEN];
arg_cmdfn* proc;
} arg_cmd_info_t;
/**** arg_xxx constructor functions *********************************/
struct arg_rem* arg_rem(const char* datatype, const char* glossary);
ARG_EXTERN struct arg_rem* arg_rem(const char* datatype, const char* glossary);
struct arg_lit* arg_lit0(const char* shortopts,
const char* longopts,
const char* glossary);
struct arg_lit* arg_lit1(const char* shortopts,
const char* longopts,
const char *glossary);
struct arg_lit* arg_litn(const char* shortopts,
const char* longopts,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary);
ARG_EXTERN struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary);
ARG_EXTERN struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary);
struct arg_key* arg_key0(const char* keyword,
int flags,
const char* glossary);
struct arg_key* arg_key1(const char* keyword,
int flags,
const char* glossary);
struct arg_key* arg_keyn(const char* keyword,
int flags,
int mincount,
int maxcount,
const char* glossary);
ARG_EXTERN struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
struct arg_int* arg_int0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_int* arg_int1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_int* arg_intn(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
struct arg_dbl* arg_dbl0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_dbl* arg_dbl1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_dbl* arg_dbln(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
struct arg_str* arg_str0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_str* arg_str1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_str* arg_strn(const char* shortopts,
const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_rex* arg_rex0(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int flags,
const char* glossary);
struct arg_rex* arg_rex1(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int flags,
const char *glossary);
struct arg_rex* arg_rexn(const char* shortopts,
ARG_EXTERN struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary);
ARG_EXTERN struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary);
ARG_EXTERN struct arg_rex* arg_rexn(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
@ -249,55 +202,70 @@ struct arg_rex* arg_rexn(const char* shortopts,
int flags,
const char* glossary);
struct arg_file* arg_file0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_file* arg_file1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_file* arg_filen(const char* shortopts,
const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary);
struct arg_date* arg_date0(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char* glossary);
struct arg_date* arg_date1(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char *glossary);
struct arg_date* arg_daten(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
ARG_EXTERN struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary);
ARG_EXTERN struct arg_date* arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary);
struct arg_end* arg_end(int maxerrors);
ARG_EXTERN struct arg_end* arg_end(int maxerrors);
#define ARG_DSTR_STATIC ((arg_dstr_freefn*)0)
#define ARG_DSTR_VOLATILE ((arg_dstr_freefn*)1)
#define ARG_DSTR_DYNAMIC ((arg_dstr_freefn*)3)
/**** other functions *******************************************/
int arg_nullcheck(void **argtable);
int arg_parse(int argc, char **argv, void **argtable);
void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix);
void arg_print_syntax(FILE *fp, void **argtable, const char *suffix);
void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix);
void arg_print_glossary(FILE *fp, void **argtable, const char *format);
void arg_print_glossary_gnu(FILE *fp, void **argtable);
void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
void arg_freetable(void **argtable, size_t n);
ARG_EXTERN int arg_nullcheck(void** argtable);
ARG_EXTERN int arg_parse(int argc, char** argv, void** argtable);
ARG_EXTERN void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix);
ARG_EXTERN void arg_print_syntax(FILE* fp, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_glossary(FILE* fp, void** argtable, const char* format);
ARG_EXTERN void arg_print_glossary_gnu(FILE* fp, void** argtable);
ARG_EXTERN void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
ARG_EXTERN void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix);
ARG_EXTERN void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix);
ARG_EXTERN void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format);
ARG_EXTERN void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable);
ARG_EXTERN void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname);
ARG_EXTERN void arg_freetable(void** argtable, size_t n);
ARG_EXTERN arg_dstr_t arg_dstr_create(void);
ARG_EXTERN void arg_dstr_destroy(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_reset(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_free(arg_dstr_t ds);
ARG_EXTERN void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc);
ARG_EXTERN void arg_dstr_cat(arg_dstr_t ds, const char* str);
ARG_EXTERN void arg_dstr_catc(arg_dstr_t ds, char c);
ARG_EXTERN void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...);
ARG_EXTERN char* arg_dstr_cstr(arg_dstr_t ds);
ARG_EXTERN void arg_cmd_init(void);
ARG_EXTERN void arg_cmd_uninit(void);
ARG_EXTERN void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description);
ARG_EXTERN void arg_cmd_unregister(const char* name);
ARG_EXTERN int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res);
ARG_EXTERN unsigned int arg_cmd_count(void);
ARG_EXTERN arg_cmd_info_t* arg_cmd_info(const char* name);
ARG_EXTERN arg_cmd_itr_t arg_cmd_itr_create(void);
ARG_EXTERN void arg_cmd_itr_destroy(arg_cmd_itr_t itr);
ARG_EXTERN int arg_cmd_itr_advance(arg_cmd_itr_t itr);
ARG_EXTERN char* arg_cmd_itr_key(arg_cmd_itr_t itr);
ARG_EXTERN arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr);
ARG_EXTERN int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k);
ARG_EXTERN void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn);
ARG_EXTERN void arg_make_get_help_msg(arg_dstr_t res);
ARG_EXTERN void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable);
ARG_EXTERN void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end);
ARG_EXTERN int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode);
ARG_EXTERN void arg_set_module_name(const char* name);
ARG_EXTERN void arg_set_module_version(int major, int minor, int patch, const char* tag);
/**** deprecated functions, for back-compatibility only ********/
void arg_free(void **argtable);
ARG_EXTERN void arg_free(void** argtable);
#ifdef __cplusplus
}

View file

@ -153,23 +153,14 @@ void CLIParserFree() {
// convertors
int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
*datalen = 0;
if (!argstr->count)
return 0;
char buf[256] = {0};
int ibuf = 0;
uint8_t buf[256] = {0};
int res = CLIParamStrToBuf(argstr, buf, maxdatalen * 2, &ibuf); // *2 because here HEX
if (res || !ibuf)
return res;
for (int i = 0; i < argstr->count; i++) {
int len = strlen(argstr->sval[i]);
memcpy(&buf[ibuf], argstr->sval[i], len);
ibuf += len;
}
buf[ibuf] = 0;
if (!ibuf)
return 0;
switch(param_gethex_to_eol(buf, 0, data, maxdatalen, datalen)) {
switch(param_gethex_to_eol((char *)buf, 0, data, maxdatalen, datalen)) {
case 1:
printf("Parameter error: Invalid HEX value.\n");
return 1;
@ -184,5 +175,31 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
return 0;
}
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
*datalen = 0;
if (!argstr->count)
return 0;
uint8_t buf[256] = {0};
int ibuf = 0;
for (int i = 0; i < argstr->count; i++) {
int len = strlen(argstr->sval[i]);
memcpy(&buf[ibuf], argstr->sval[i], len);
ibuf += len;
}
buf[ibuf] = 0;
if (!ibuf)
return 0;
if (ibuf > maxdatalen)
return 2;
memcpy(data, buf, ibuf);
*datalen = ibuf;
return 0;
}

View file

@ -17,7 +17,9 @@
#define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
#define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count)
#define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count)
#define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0])
#define arg_get_int_def(n,def)(arg_get_int_count(n)?(arg_get_int(n)):(def))
#define arg_get_str(n)((struct arg_str*)argtable[n])
#define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0]))
@ -25,8 +27,9 @@
#define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary)))
#define CLIExecWithReturn(cmd, atbl, ifempty) if (CLIParserParseString(cmd, atbl, arg_getsize(atbl), ifempty)){CLIParserFree();return 0;}
#define CLIGetStrBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;}
#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;}
#define CLIGetHexBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;}
#define CLIGetHexWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;}
#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;}
extern int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp);
extern int CLIParserParseString(const char* str, void* argtable[], size_t vargtableLen, bool allowEmptyExec);
@ -35,3 +38,4 @@ extern int CLIParserParseArg(int argc, char **argv, void* argtable[], size_t var
extern void CLIParserFree();
extern int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);
extern int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);

View file

@ -367,18 +367,20 @@ int Cmdmandecoderaw(const char *Cmd)
return 1;
}
//by marshmellow
//biphase decode
//take 01 or 10 = 0 and 11 or 00 = 1
//takes 2 arguments "offset" default = 0 if 1 it will shift the decode by one bit
// and "invert" default = 0 if 1 it will invert output
// the argument offset allows us to manually shift if the output is incorrect - [EDIT: now auto detects]
/**
* @author marshmellow
* biphase decode
* decdoes 01 or 10 to 0 and 11 or 00 to 1
* param offset adjust start position
* param invert invert output
* param maxErr maximum tolerated errors
*/
int CmdBiphaseDecodeRaw(const char *Cmd)
{
size_t size=0;
int offset=0, invert=0, maxErr=20, errCnt=0;
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') {
if (strlen(Cmd) > 7 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: data biphaserawdecode [offset] [invert] [maxErr]");
PrintAndLog(" Converts 10 or 01 to 1 and 11 or 00 to 0");
PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)");
@ -427,7 +429,7 @@ int CmdBiphaseDecodeRaw(const char *Cmd)
int ASKbiphaseDemod(const char *Cmd, bool verbose)
{
//ask raw demod GraphBuffer first
int offset=0, clk=0, invert=0, maxErr=0;
int offset=0, clk=0, invert=0, maxErr=100;
sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr);
uint8_t BitStream[MAX_GRAPH_TRACE_LEN];
@ -1204,13 +1206,16 @@ int getSamples(int n, bool silent)
uint8_t bits_per_sample = 8;
//Old devices without this feature would send 0 at arg[0]
if(response.arg[0] > 0)
{
if(response.arg[0] > 0) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
sample_config *sc = (sample_config *) response.d.asBytes;
#pragma GCC diagnostic pop
if (!silent) PrintAndLog("Samples @ %d bits/smpl, decimation 1:%d ", sc->bits_per_sample
, sc->decimation);
bits_per_sample = sc->bits_per_sample;
}
if(bits_per_sample < 8)
{
if (!silent) PrintAndLog("Unpacking...");

View file

@ -11,16 +11,12 @@
#include "cmdhf.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "usb_cmd.h"
#include "comms.h"
#include "util.h"
#include "ui.h"
#include "iso14443crc.h"
#include "parity.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cliparser/cliparser.h"
#include "cmdhf14a.h"
#include "cmdhf14b.h"
#include "cmdhf15.h"
@ -28,11 +24,14 @@
#include "cmdhflegic.h"
#include "cmdhficlass.h"
#include "cmdhfmf.h"
#include "cmdhfmfp.h"
#include "cmdhfmfu.h"
#include "cmdhftopaz.h"
#include "protocols.h"
#include "emv/cmdemv.h"
#include "cmdhflist.h"
#include "cmdhffido.h"
#include "cmddata.h"
#include "graph.h"
#include "fpga.h"
static int CmdHelp(const char *Cmd);
@ -43,510 +42,6 @@ int CmdHFTune(const char *Cmd)
return 0;
}
/**
* @brief iso14443B_CRC_check Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
if(len <= 2) return 2;
ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2);
if(b1 != data[len-2] || b2 != data[len-1]) {
return 0;
} else {
return 1;
}
}
/**
* @brief iclass_CRC_Ok Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes
uint8_t b1, b2;
if(!isResponse)//Commands to tag
{
/**
These commands should have CRC. Total length leftmost
4 READ
4 READ4
12 UPDATE - unsecured, ends with CRC16
14 UPDATE - secured, ends with signature instead
4 PAGESEL
**/
if(len == 4 || len == 12)//Covers three of them
{
//Don't include the command byte
ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2);
return b1 == data[len -2] && b2 == data[len-1];
}
return 2;
}else{
/**
These tag responses should have CRC. Total length leftmost
10 READ data[8] crc[2]
34 READ4 data[32]crc[2]
10 UPDATE data[8] crc[2]
10 SELECT csn[8] crc[2]
10 IDENTIFY asnb[8] crc[2]
10 PAGESEL block1[8] crc[2]
10 DETECT csn[8] crc[2]
These should not
4 CHECK chip_response[4]
8 READCHECK data[8]
1 ACTALL sof[1]
1 ACT sof[1]
In conclusion, without looking at the command; any response
of length 10 or 34 should have CRC
**/
if(len != 10 && len != 34) return true;
ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2);
return b1 == data[len -2] && b2 == data[len-1];
}
}
bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen)
{
return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen);
}
bool next_record_is_response(uint16_t tracepos, uint8_t *trace)
{
uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t)));
return(next_records_datalen & 0x8000);
}
bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len)
{
#define MAX_TOPAZ_READER_CMD_LEN 16
uint32_t last_timestamp = timestamp + *duration;
if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false;
memcpy(topaz_reader_command, frame, *data_len);
while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) {
uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos));
*tracepos += sizeof(uint32_t);
uint16_t next_duration = *((uint16_t *)(trace + *tracepos));
*tracepos += sizeof(uint16_t);
uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF;
*tracepos += sizeof(uint16_t);
uint8_t *next_frame = (trace + *tracepos);
*tracepos += next_data_len;
if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) {
memcpy(topaz_reader_command + *data_len, next_frame, next_data_len);
*data_len += next_data_len;
last_timestamp = next_timestamp + next_duration;
} else {
// rewind and exit
*tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t);
break;
}
uint16_t next_parity_len = (next_data_len-1)/8 + 1;
*tracepos += next_parity_len;
}
*duration = last_timestamp - timestamp;
return true;
}
uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes)
{
bool isResponse;
uint16_t data_len, parity_len;
uint32_t duration;
uint8_t topaz_reader_command[9];
uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
char explanation[30] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
first_timestamp = *((uint32_t *)(trace));
timestamp = *((uint32_t *)(trace + tracepos));
tracepos += 4;
duration = *((uint16_t *)(trace + tracepos));
tracepos += 2;
data_len = *((uint16_t *)(trace + tracepos));
tracepos += 2;
if (data_len & 0x8000) {
data_len &= 0x7fff;
isResponse = true;
} else {
isResponse = false;
}
parity_len = (data_len-1)/8 + 1;
if (tracepos + data_len + parity_len > traceLen) {
return traceLen;
}
uint8_t *frame = trace + tracepos;
tracepos += data_len;
uint8_t *parityBytes = trace + tracepos;
tracepos += parity_len;
if (protocol == TOPAZ && !isResponse) {
// topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
// merge them:
if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) {
frame = topaz_reader_command;
}
}
//Check the CRC status
uint8_t crcStatus = 2;
if (data_len > 2) {
switch (protocol) {
case ICLASS:
crcStatus = iclass_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443B:
case TOPAZ:
crcStatus = iso14443B_CRC_check(isResponse, frame, data_len);
break;
case PROTO_MIFARE:
crcStatus = mifare_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443A:
crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
break;
default:
break;
}
}
//0 CRC-command, CRC not ok
//1 CRC-command, CRC ok
//2 Not crc-command
//--- Draw the data column
//char line[16][110];
char line[16][110];
for (int j = 0; j < data_len && j/16 < 16; j++) {
uint8_t parityBits = parityBytes[j>>3];
if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]);
} else {
snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]);
}
}
if (markCRCBytes) {
if(crcStatus == 0 || crcStatus == 1)
{//CRC-command
char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4);
(*pos1) = '[';
char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4);
sprintf(pos2, "%c", ']');
}
}
if(data_len == 0)
{
if(data_len == 0){
sprintf(line[0],"<empty trace - possible error>");
}
}
//--- Draw the CRC column
char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " "));
EndOfTransmissionTimestamp = timestamp + duration;
if (protocol == PROTO_MIFARE)
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
if(!isResponse)
{
switch(protocol) {
case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break;
case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break;
case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break;
case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break;
default: break;
}
}
int num_lines = MIN((data_len - 1)/16 + 1, 16);
for (int j = 0; j < num_lines ; j++) {
if (j == 0) {
PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s",
(timestamp - first_timestamp),
(EndOfTransmissionTimestamp - first_timestamp),
(isResponse ? "Tag" : "Rdr"),
line[j],
(j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : "");
} else {
PrintAndLog(" | | |%-64s | %s| %s",
line[j],
(j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : "");
}
}
if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) {
memset(explanation, 0x00, sizeof(explanation));
if (!isResponse) {
explanation[0] = '>';
annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen);
}
uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen);
PrintAndLog(" | * | dec |%-64s | %-4s| %s",
sprint_hex(mfData, mfDataLen),
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
(true) ? explanation : "");
};
if (is_last_record(tracepos, trace, traceLen)) return traceLen;
if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) {
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d",
(EndOfTransmissionTimestamp - first_timestamp),
(next_timestamp - first_timestamp),
" ",
(next_timestamp - EndOfTransmissionTimestamp));
}
return tracepos;
}
int CmdHFList(const char *Cmd)
{
#ifdef WITH_SMARTCARD
PrintAndLog("TEST_WITH_SMARTCARD");
#endif
#ifdef WITH_TEST
PrintAndLog("TEST_WITH_TEST");
#endif
bool showWaitCycles = false;
bool markCRCBytes = false;
bool loadFromFile = false;
bool saveToFile = false;
char param1 = '\0';
char param2 = '\0';
char param3 = '\0';
char type[40] = {0};
char filename[FILE_PATH_SIZE] = {0};
uint8_t protocol = 0;
// parse command line
int tlen = param_getstr(Cmd, 0, type, sizeof(type));
if (param_getlength(Cmd, 1) == 1) {
param1 = param_getchar(Cmd, 1);
} else {
param_getstr(Cmd, 1, filename, sizeof(filename));
}
if (param_getlength(Cmd, 2) == 1) {
param2 = param_getchar(Cmd, 2);
} else if (strlen(filename) == 0) {
param_getstr(Cmd, 2, filename, sizeof(filename));
}
if (param_getlength(Cmd, 3) == 1) {
param3 = param_getchar(Cmd, 3);
} else if (strlen(filename) == 0) {
param_getstr(Cmd, 3, filename, sizeof(filename));
}
// Validate param1
bool errors = false;
if(tlen == 0) {
errors = true;
}
if(param1 == 'h'
|| (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l')
|| (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l')
|| (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) {
errors = true;
}
if(!errors) {
if(strcmp(type, "iclass") == 0) {
protocol = ICLASS;
} else if(strcmp(type, "mf") == 0) {
protocol = PROTO_MIFARE;
} else if(strcmp(type, "14a") == 0) {
protocol = ISO_14443A;
} else if(strcmp(type, "14b") == 0) {
protocol = ISO_14443B;
} else if(strcmp(type,"topaz") == 0) {
protocol = TOPAZ;
} else if(strcmp(type,"raw") == 0) {
protocol = -1; //No crc, no annotations
} else if (strcmp(type, "save") == 0) {
saveToFile = true;
} else {
errors = true;
}
}
if (param1 == 'f' || param2 == 'f' || param3 == 'f') {
showWaitCycles = true;
}
if (param1 == 'c' || param2 == 'c' || param3 == 'c') {
markCRCBytes = true;
}
if (param1 == 'l' || param2 == 'l' || param3 == 'l') {
loadFromFile = true;
}
if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
errors = true;
}
if (loadFromFile && saveToFile) {
errors = true;
}
if (errors) {
PrintAndLog("List or save protocol data.");
PrintAndLog("Usage: hf list <protocol> [f] [c] [l <filename>]");
PrintAndLog(" hf list save <filename>");
PrintAndLog(" f - show frame delay times as well");
PrintAndLog(" c - mark CRC bytes");
PrintAndLog(" l - load data from file instead of trace buffer");
PrintAndLog(" save - save data to file");
PrintAndLog("Supported <protocol> values:");
PrintAndLog(" raw - just show raw data without annotations");
PrintAndLog(" 14a - interpret data as iso14443a communications");
PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream");
PrintAndLog(" 14b - interpret data as iso14443b communications");
PrintAndLog(" iclass - interpret data as iclass communications");
PrintAndLog(" topaz - interpret data as topaz communications");
PrintAndLog("");
PrintAndLog("example: hf list 14a f");
PrintAndLog("example: hf list iclass");
PrintAndLog("example: hf list save myCardTrace.trc");
PrintAndLog("example: hf list 14a l myCardTrace.trc");
return 0;
}
uint8_t *trace;
uint32_t tracepos = 0;
uint32_t traceLen = 0;
if (loadFromFile) {
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
FILE *tracefile = NULL;
size_t bytes_read;
trace = malloc(TRACE_CHUNK_SIZE);
if (trace == NULL) {
PrintAndLog("Cannot allocate memory for trace");
return 2;
}
if ((tracefile = fopen(filename,"rb")) == NULL) {
PrintAndLog("Could not open file %s", filename);
free(trace);
return 0;
}
while (!feof(tracefile)) {
bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile);
traceLen += bytes_read;
if (!feof(tracefile)) {
uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
fclose(tracefile);
return 2;
}
trace = p;
}
}
fclose(tracefile);
} else {
trace = malloc(USB_CMD_DATA_SIZE);
// Query for the size of the trace
UsbCommand response;
GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false);
traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(trace, traceLen);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
return 2;
}
trace = p;
GetFromBigBuf(trace, traceLen, 0, NULL, -1, false);
}
}
if (saveToFile) {
FILE *tracefile = NULL;
if ((tracefile = fopen(filename,"wb")) == NULL) {
PrintAndLog("Could not create file %s", filename);
return 1;
}
fwrite(trace, 1, traceLen, tracefile);
PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename);
fclose(tracefile);
} else {
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLog("");
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)");
PrintAndLog("iClass - Timings are not as accurate");
PrintAndLog("");
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |");
PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|");
ClearAuthData();
while(tracepos < traceLen)
{
tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes);
}
}
free(trace);
return 0;
}
int CmdHFSearch(const char *Cmd){
int ans = 0;
PrintAndLog("");
@ -555,7 +50,7 @@ int CmdHFSearch(const char *Cmd){
PrintAndLog("\nValid ISO14443A Tag Found - Quiting Search\n");
return ans;
}
ans = HFiClassReader("", false, false);
ans = HFiClassReader(false, false);
if (ans) {
PrintAndLog("\nValid iClass Tag (or PicoPass Tag) Found - Quiting Search\n");
return ans;
@ -566,11 +61,16 @@ int CmdHFSearch(const char *Cmd){
return ans;
}
//14b is longest test currently (and rarest chip type) ... put last
ans = HF14BInfo(false);
ans = infoHF14B(false);
if (ans) {
PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n");
return ans;
}
ans = CmdLegicRFRead("");
if (ans == 0) {
PrintAndLog("\nValid Legic Tag Found - Quiting Search\n");
return ans;
}
PrintAndLog("\nno known/supported 13.56 MHz tags found\n");
return 0;
}
@ -583,22 +83,75 @@ int CmdHFSnoop(const char *Cmd)
return 0;
}
// static void InterpolateShannon(int *source, size_t source_len, int *dest, size_t dest_len)
// {
// int *buf = (int*)malloc(source_len * sizeof(int));
// memcpy(buf, source, source_len * sizeof(int));
// for (int i = 0; i < source_len; i++) {
// buf[i] += 128;
// }
// for (int i = 0; i < dest_len; i++) {
// float value = 0.0;
// for (int j = 0; j < source_len; j++) {
// if (i * source_len == j * dest_len) { // sin(0) / 0 = 1
// value += (float)buf[j];
// } else {
// value += (float)buf[j] * sin(((float)i*source_len/dest_len-j)*3.1415) / (((float)i*source_len/dest_len-j)*3.1415);
// }
// }
// dest[i] = value - 128;
// }
// free(buf);
// }
static int CmdHFPlot(const char *Cmd)
{
CLIParserInit("hf plot",
"Plots HF signal after RF signal path and A/D conversion.",
"This can be used after any hf command and will show the last few milliseconds of the HF signal.\n"
"Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n");
void* argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
uint8_t buf[FPGA_TRACE_SIZE];
if (GetFromFpgaRAM(buf, FPGA_TRACE_SIZE)) {
for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) {
GraphBuffer[i] = (int)buf[i] - 128;
}
GraphTraceLen = FPGA_TRACE_SIZE;
// InterpolateShannon(GraphBuffer, FPGA_TRACE_SIZE, GraphBuffer, FPGA_TRACE_SIZE*8/7);
// GraphTraceLen = FPGA_TRACE_SIZE*8/7;
ShowGraphWindow();
RepaintGraphWindow();
}
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"},
{"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"},
{"14a", CmdHF14A, 0, "{ ISO14443A RFIDs... }"},
{"14b", CmdHF14B, 0, "{ ISO14443B RFIDs... }"},
{"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"},
{"epa", CmdHFEPA, 1, "{ German Identification Card... }"},
{"emv", CmdHFEMV, 1, "{ EMV cards... }"},
{"epa", CmdHFEPA, 0, "{ German Identification Card... }"},
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
{"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"},
{"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"mfp", CmdHFMFP, 0, "{ MIFARE Plus RFIDs... }"},
{"topaz", CmdHFTopaz, 0, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"fido", CmdHFFido, 0, "{ FIDO and FIDO2 authenticators... }"},
{"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"},
{"list", CmdHFList, 1, "List protocol data in trace buffer"},
{"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"},
{"plot", CmdHFPlot, 0, "Plot signal"},
{"search", CmdHFSearch, 0, "Search for known HF tags [preliminary]"},
{"snoop", CmdHFSnoop, 0, "<samples to skip (10000)> <triggers to skip (1)> Generic HF Snoop"},
{NULL, NULL, 0, NULL}
};

View file

@ -13,5 +13,5 @@
int CmdHF(const char *Cmd);
int CmdHFTune(const char *Cmd);
int CmdHFList(const char *Cmd);
#endif

View file

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2011, 2017 Merlok
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
// 2011, 2017 - 2019 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -27,108 +27,18 @@
#include "cmdmain.h"
#include "mifare.h"
#include "cmdhfmfu.h"
#include "mifarehost.h"
#include "mifare/mifarehost.h"
#include "cliparser/cliparser.h"
#include "emv/apduinfo.h"
#include "emv/emvcore.h"
#include "taginfo.h"
static int CmdHelp(const char *Cmd);
static int waitCmd(uint8_t iLen);
// structure and database for uid -> tagtype lookups
typedef struct {
uint8_t uid;
char* desc;
} manufactureName;
static const manufactureName manufactureMapping[] = {
// ID, "Vendor Country"
{ 0x01, "Motorola UK" },
{ 0x02, "ST Microelectronics SA France" },
{ 0x03, "Hitachi, Ltd Japan" },
{ 0x04, "NXP Semiconductors Germany" },
{ 0x05, "Infineon Technologies AG Germany" },
{ 0x06, "Cylink USA" },
{ 0x07, "Texas Instrument France" },
{ 0x08, "Fujitsu Limited Japan" },
{ 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" },
{ 0x0A, "NEC Japan" },
{ 0x0B, "Oki Electric Industry Co. Ltd Japan" },
{ 0x0C, "Toshiba Corp. Japan" },
{ 0x0D, "Mitsubishi Electric Corp. Japan" },
{ 0x0E, "Samsung Electronics Co. Ltd Korea" },
{ 0x0F, "Hynix / Hyundai, Korea" },
{ 0x10, "LG-Semiconductors Co. Ltd Korea" },
{ 0x11, "Emosyn-EM Microelectronics USA" },
{ 0x12, "INSIDE Technology France" },
{ 0x13, "ORGA Kartensysteme GmbH Germany" },
{ 0x14, "SHARP Corporation Japan" },
{ 0x15, "ATMEL France" },
{ 0x16, "EM Microelectronic-Marin SA Switzerland" },
{ 0x17, "KSW Microtec GmbH Germany" },
{ 0x18, "ZMD AG Germany" },
{ 0x19, "XICOR, Inc. USA" },
{ 0x1A, "Sony Corporation Japan Identifier Company Country" },
{ 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" },
{ 0x1C, "Emosyn USA" },
{ 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" },
{ 0x1E, "Magellan Technology Pty Limited Australia" },
{ 0x1F, "Melexis NV BO Switzerland" },
{ 0x20, "Renesas Technology Corp. Japan" },
{ 0x21, "TAGSYS France" },
{ 0x22, "Transcore USA" },
{ 0x23, "Shanghai belling corp., ltd. China" },
{ 0x24, "Masktech Germany Gmbh Germany" },
{ 0x25, "Innovision Research and Technology Plc UK" },
{ 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" },
{ 0x27, "Cypak AB Sweden" },
{ 0x28, "Ricoh Japan" },
{ 0x29, "ASK France" },
{ 0x2A, "Unicore Microsystems, LLC Russian Federation" },
{ 0x2B, "Dallas Semiconductor/Maxim USA" },
{ 0x2C, "Impinj, Inc. USA" },
{ 0x2D, "RightPlug Alliance USA" },
{ 0x2E, "Broadcom Corporation USA" },
{ 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" },
{ 0x30, "BeeDar Technology Inc. USA" },
{ 0x31, "RFIDsec Denmark" },
{ 0x32, "Schweizer Electronic AG Germany" },
{ 0x33, "AMIC Technology Corp Taiwan" },
{ 0x34, "Mikron JSC Russia" },
{ 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" },
{ 0x36, "IDS Microchip AG Switzerland" },
{ 0x37, "Kovio USA" },
{ 0x38, "HMT Microelectronic Ltd Switzerland Identifier Company Country" },
{ 0x39, "Silicon Craft Technology Thailand" },
{ 0x3A, "Advanced Film Device Inc. Japan" },
{ 0x3B, "Nitecrest Ltd UK" },
{ 0x3C, "Verayo Inc. USA" },
{ 0x3D, "HID Global USA" },
{ 0x3E, "Productivity Engineering Gmbh Germany" },
{ 0x3F, "Austriamicrosystems AG (reserved) Austria" },
{ 0x40, "Gemalto SA France" },
{ 0x41, "Renesas Electronics Corporation Japan" },
{ 0x42, "3Alogics Inc Korea" },
{ 0x43, "Top TroniQ Asia Limited Hong Kong" },
{ 0x44, "Gentag Inc (USA) USA" },
{ 0x00, "no tag-info available" } // must be the last entry
};
// get a product description based on the UID
// uid[8] tag uid
// returns description of the best match
char* getTagInfo(uint8_t uid) {
int i;
int len = sizeof(manufactureMapping) / sizeof(manufactureName);
for ( i = 0; i < len; ++i )
if ( uid == manufactureMapping[i].uid)
return manufactureMapping[i].desc;
//No match, return default
return manufactureMapping[len-1].desc;
}
// iso14a apdu input frame length
static uint16_t frameLength = 0;
uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
int CmdHF14AList(const char *Cmd)
{
@ -136,6 +46,45 @@ int CmdHF14AList(const char *Cmd)
return 0;
}
int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_NACK, &resp);
memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if (select_status == 0) {
PrintAndLog("E->iso14443a card select failed");
return 1;
}
if (select_status == 2) {
PrintAndLog("E->Card doesn't support iso14443-4 mode");
return 1;
}
if (select_status == 3) {
PrintAndLog("E->Card doesn't support standard iso14443-3 anticollision");
PrintAndLog("\tATQA : %02x %02x", card->atqa[1], card->atqa[0]);
return 1;
}
PrintAndLog(" UID: %s", sprint_hex(card->uid, card->uidlen));
PrintAndLog("ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
PrintAndLog(" SAK: %02x [%" PRIu64 "]", card->sak, resp.arg[0]);
if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
PrintAndLog("E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len));
return 1;
}
PrintAndLog(" ATS: %s", sprint_hex(card->ats, card->ats_len));
return 0;
}
int CmdHF14AReader(const char *Cmd) {
uint32_t cm = ISO14A_CONNECT;
bool leaveSignalON = false;
@ -207,13 +156,17 @@ int CmdHF14AReader(const char *Cmd) {
return 0;
}
int CmdHF14AInfo(const char *Cmd)
{
int CmdHF14AInfo(const char *Cmd) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
if (!WaitForResponseTimeout(CMD_NACK, &resp, 500)) {
if (Cmd[0] != 's') PrintAndLog("Error: No response from Proxmark.\n");
return 0;
}
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
@ -268,7 +221,7 @@ int CmdHF14AInfo(const char *Cmd)
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
WaitForResponse(CMD_NACK,&resp);
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
@ -324,7 +277,7 @@ int CmdHF14AInfo(const char *Cmd)
// Double & triple sized UID, can be mapped to a manufacturer.
// HACK: does this apply for Ultralight cards?
if (card.uidlen > 4) {
PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0]));
PrintAndLog("MANUFACTURER : %s", getManufacturerName(card.uid[0]));
}
// try to request ATS even if tag claims not to support it
@ -363,10 +316,7 @@ int CmdHF14AInfo(const char *Cmd)
"TC1 is%s present, FSCI is %d (FSC = %ld)",
(ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"),
fsci,
fsci < 5 ? (fsci - 2) * 8 :
fsci < 8 ? (fsci - 3) * 32 :
fsci == 8 ? 256 :
-1
fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1
);
}
pos = 2;
@ -516,7 +466,7 @@ int CmdHF14ACUIDs(const char *Cmd)
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
WaitForResponse(CMD_NACK,&resp);
iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes;
@ -618,6 +568,7 @@ int CmdHF14ASim(const char *Cmd)
return 0;
}
int CmdHF14ASnoop(const char *Cmd) {
int param = 0;
@ -643,80 +594,256 @@ int CmdHF14ASnoop(const char *Cmd) {
return 0;
}
void DropField() {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
SendCommand(&c);
}
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
static bool responseNum = false;
uint16_t cmdc = 0;
*dataoutlen = 0;
if (activateField) {
cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
responseNum = false;
UsbCommand resp;
// Anticollision + SELECT card
UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_CLEAR_TRACE, 0, 0}};
SendCommand(&ca);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
return 1;
}
// check result
if (resp.arg[0] == 0) {
PrintAndLog("14aRAW ERROR: No card in field.");
return 1;
}
if (resp.arg[0] != 1 && resp.arg[0] != 2) {
PrintAndLog("14aRAW ERROR: card not in iso14443-4. res=%d.", resp.arg[0]);
return 1;
}
if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS
UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}};
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
memcpy(cr.d.asBytes, rats, 2);
SendCommand(&cr);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] <= 0) { // ats_len
PrintAndLog("14aRAW ERROR: Can't get ATS.");
return 1;
}
}
}
if (leaveSignalON)
cmdc |= ISO14A_NO_DISCONNECT;
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
// here length USB_CMD_DATA_SIZE=512
// timeout must be authomatically set by "get ATS"
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | cmdc, (datainlen & 0xFFFF), 0}};
memcpy(c.d.asBytes, datain, datainlen);
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}};
uint8_t header[] = {0x0a | responseNum, 0x00};
responseNum ^= 1;
memcpy(c.d.asBytes, header, 2);
memcpy(&c.d.asBytes[2], datain, datainlen);
SendCommand(&c);
uint8_t *recv;
UsbCommand resp;
if (activateField) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("APDU ERROR: Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] != 1) {
PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]);
return 1;
}
}
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
if(!iLen) {
PrintAndLog("14aRAW ERROR: No card response.");
return 1;
}
*dataoutlen = iLen - 2;
if (*dataoutlen < 0)
*dataoutlen = 0;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
return 2;
}
if (recv[0] != header[0]) {
PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]);
return 2;
}
memcpy(dataout, &recv[2], *dataoutlen);
// CRC Check
if (iLen == -1) {
PrintAndLog("14aRAW ERROR: ISO 14443A CRC error.");
return 3;
}
} else {
PrintAndLog("14aRAW ERROR: Reply timeout.");
return 4;
}
return 0;
}
static int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) {
UsbCommand resp;
frameLength = 0;
if (card)
memset(card, 0, sizeof(iso14a_card_select_t));
DropField();
// Anticollision + SELECT card
UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&ca);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(ERR, "Proxmark connection timeout.");
return 1;
}
// check result
if (resp.arg[0] == 0) {
PrintAndLogEx(ERR, "No card in field.");
return 1;
}
if (resp.arg[0] != 1 && resp.arg[0] != 2) {
PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.arg[0]);
return 1;
}
if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// try to get ATS although SAK indicated that it is not ISO14443-4 compliant
UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}};
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
memcpy(cr.d.asBytes, rats, 2);
SendCommand(&cr);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(ERR, "Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] <= 0) { // ats_len
PrintAndLogEx(ERR, "Can't get ATS.");
return 1;
}
}
// get frame length from ATS
iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.d.asBytes;
if (vcard->ats_len > 1) {
uint8_t fsci = vcard->ats[1] & 0x0f;
if (fsci < sizeof(atsFSC))
frameLength = atsFSC[fsci];
}
if (card) {
memcpy(card, vcard, sizeof(iso14a_card_select_t));
}
if (disconnect) {
DropField();
}
return 0;
}
static int ExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout)
{
*chainingout = false;
if (activateField) {
// select with no disconnect and set frameLength
int selres = SelectCard14443_4(false, NULL);
if (selres)
return selres;
}
uint16_t cmdc = 0;
if (chainingin)
cmdc = ISO14A_SEND_CHAINING;
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
// here length USB_CMD_DATA_SIZE=512
// timeout must be authomatically set by "get ATS"
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}};
memcpy(c.d.asBytes, datain, datainlen);
SendCommand(&c);
uint8_t *recv;
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
uint8_t res = resp.arg[1];
int dlen = iLen - 2;
if (dlen < 0)
dlen = 0;
*dataoutlen += dlen;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
return 2;
}
memcpy(dataout, recv, *dataoutlen);
// I-block ACK
if ((res & 0xf2) == 0xa2) {
*dataoutlen = 0;
*chainingout = true;
return 0;
}
if(!iLen) {
PrintAndLog("APDU ERROR: No APDU response.");
return 1;
}
// check apdu length
if (iLen < 2 && iLen >= 0) {
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
return 2;
}
// check block TODO
if (iLen == -2) {
PrintAndLog("APDU ERROR: Block type mismatch.");
return 2;
}
memcpy(dataout, recv, dlen);
// chaining
if ((res & 0x10) != 0) {
*chainingout = true;
}
// CRC Check
if (iLen == -1) {
PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
return 3;
}
// check apdu length
if (iLen < 4) {
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
return 2;
}
} else {
PrintAndLog("APDU ERROR: Reply timeout.");
return 4;
@ -725,24 +852,107 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
return 0;
}
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0;
bool chaining = false;
int res;
// 3 byte here - 1b framing header, 2b crc16
if ( (frameLength && (datainlen > frameLength - 3)) || (datainlen > USB_CMD_DATA_SIZE - 3) ) {
int clen = 0;
bool vActivateField = activateField;
do {
int vlen = MIN(frameLength - 3, datainlen - clen);
bool chainBlockNotLast = ((clen + vlen) < datainlen);
*dataoutlen = 0;
res = ExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining);
if (res) {
if (!leaveSignalON)
DropField();
return 200;
}
// check R-block ACK
if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) {
if (!leaveSignalON)
DropField();
return 201;
}
clen += vlen;
vActivateField = false;
if (*dataoutlen) {
if (clen != datainlen)
PrintAndLogEx(WARNING, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen);
break;
}
} while (clen < datainlen);
} else {
res = ExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining);
if (res) {
if (!leaveSignalON)
DropField();
return res;
}
}
while (chaining) {
// I-block with chaining
res = ExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining);
if (res) {
if (!leaveSignalON)
DropField();
return 100;
}
}
if (!leaveSignalON)
DropField();
return 0;
}
// ISO14443-4. 7. Half-duplex block transmission protocol
int CmdHF14AAPDU(const char *cmd) {
uint8_t data[USB_CMD_DATA_SIZE];
int datalen = 0;
uint8_t header[5];
int headerlen = 0;
bool activateField = false;
bool leaveSignalON = false;
bool decodeTLV = false;
bool decodeAPDU = false;
bool makeAPDU = false;
bool extendedAPDU = false;
int le = 0;
int res = 0;
CLIParserInit("hf 14a apdu",
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)",
"Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n");
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013",
"Examples:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"
"\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode APDU\n"
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard APDU\n"
"\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended APDU\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "activate field and select card"),
arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
arg_strx1(NULL, NULL, "<APDU (hex)>", NULL),
arg_lit0("dD", "decapdu", "decode APDU request if it possible"),
arg_str0("mM", "make", "<head (CLA INS P1 P2) hex>", "make APDU with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"),
arg_int0("lL", "le", "<Le (int)>", "Le APDU parameter (requires `-m`)"),
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "APDU (without `-m`), or data (with `-m`)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
@ -750,15 +960,71 @@ int CmdHF14AAPDU(const char *cmd) {
activateField = arg_get_lit(1);
leaveSignalON = arg_get_lit(2);
decodeTLV = arg_get_lit(3);
// len = data + PCB(1b) + CRC(2b)
CLIGetStrBLessWithReturn(4, data, &datalen, 1 + 2);
decodeAPDU = arg_get_lit(4);
res = CLIParamHexToBuf(arg_get_str(5), header, sizeof(header), &headerlen);
makeAPDU = headerlen > 0;
if (res || (makeAPDU && headerlen != 4)) {
PrintAndLogEx(ERR, "header length must be exactly 4 bytes");
CLIParserFree();
return 1;
}
extendedAPDU = arg_get_lit(6);
le = arg_get_int_def(7, 0);
if (makeAPDU) {
uint8_t apdudata[USB_CMD_DATA_SIZE] = {0};
int apdudatalen = 0;
CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2);
APDUStruct apdu;
apdu.cla = header[0];
apdu.ins = header[1];
apdu.p1 = header[2];
apdu.p2 = header[3];
apdu.lc = apdudatalen;
apdu.data = apdudata;
apdu.extended_apdu = extendedAPDU;
apdu.le = le;
if (APDUEncode(&apdu, data, &datalen)) {
PrintAndLogEx(ERR, "can't make apdu with provided parameters.");
CLIParserFree();
return 2;
}
} else {
if (extendedAPDU) {
PrintAndLogEx(ERR, "`-e` without `-m`.");
CLIParserFree();
return 3;
}
if (le > 0) {
PrintAndLogEx(ERR, "`-l` without `-m`.");
CLIParserFree();
return 3;
}
// len = data + PCB(1b) + CRC(2b)
CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2);
}
CLIParserFree();
// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]);
PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
if (decodeAPDU) {
APDUStruct apdu;
if (APDUDecode(data, datalen, &apdu) == 0)
APDUPrint(apdu);
else
PrintAndLogEx(WARNING, "can't decode APDU.");
}
res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
if (res)
return res;

View file

@ -14,17 +14,21 @@
#include <stdint.h>
#include <stdbool.h>
#include "mifare.h"
int CmdHF14A(const char *Cmd);
int CmdHF14AList(const char *Cmd);
int CmdHF14AMifare(const char *Cmd);
int CmdHF14AReader(const char *Cmd);
extern int CmdHF14A(const char *Cmd);
extern int CmdHF14AMfDbg(const char* cmd);
extern int CmdHF14AList(const char *Cmd);
extern int CmdHF14AMifare(const char *Cmd);
extern int CmdHF14AReader(const char *Cmd);
extern int CmdHF14AInfo(const char *Cmd);
int CmdHF14ASim(const char *Cmd);
int CmdHF14ASnoop(const char *Cmd);
char* getTagInfo(uint8_t uid);
extern int CmdHF14ASim(const char *Cmd);
extern int CmdHF14ASnoop(const char *Cmd);
extern void DropField();
extern int Hf14443_4aGetCardData(iso14a_card_select_t * card);
extern int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif

View file

@ -15,6 +15,7 @@
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include "iso14443crc.h"
#include "comms.h"
#include "graph.h"
@ -22,73 +23,71 @@
#include "ui.h"
#include "cmdparser.h"
#include "cmdmain.h"
#include "cmdhf14a.h"
#include "taginfo.h"
static int CmdHelp(const char *Cmd);
int CmdHF14BList(const char *Cmd)
{
int CmdHF14BList(const char *Cmd) {
PrintAndLog("Deprecated command, use 'hf list 14b' instead");
return 0;
}
int CmdHF14BSim(const char *Cmd)
{
int CmdHF14BSim(const char *Cmd) {
UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B};
clearCommandBuffer();
SendCommand(&c);
return 0;
}
int CmdHF14BSnoop(const char *Cmd)
{
int CmdHF14BSnoop(const char *Cmd) {
UsbCommand c = {CMD_SNOOP_ISO_14443B};
clearCommandBuffer();
SendCommand(&c);
return 0;
}
/* New command to read the contents of a SRI512 tag
* SRI512 tags are ISO14443-B modulated memory tags,
* this command just dumps the contents of the memory
*/
int CmdSri512Read(const char *Cmd)
{
int CmdSri512Read(const char *Cmd) {
UsbCommand c = {CMD_READ_SRI512_TAG, {strtol(Cmd, NULL, 0), 0, 0}};
clearCommandBuffer();
SendCommand(&c);
return 0;
}
/* New command to read the contents of a SRIX4K tag
* SRIX4K tags are ISO14443-B modulated memory tags,
* this command just dumps the contents of the memory/
*/
int CmdSrix4kRead(const char *Cmd)
{
int CmdSrix4kRead(const char *Cmd) {
UsbCommand c = {CMD_READ_SRIX4K_TAG, {strtol(Cmd, NULL, 0), 0, 0}};
clearCommandBuffer();
SendCommand(&c);
return 0;
}
int rawClose(void){
static bool switch_off_field_14b(void) {
UsbCommand resp;
UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}};
clearCommandBuffer();
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
return 0;
return false;
}
return 0;
return false;
}
int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datalen, bool verbose) {
UsbCommand resp;
UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv,power
if(*crc)
{
if (*crc) {
uint8_t first, second;
ComputeCrc14443(CRC_14443_B, data, *datalen, &first, &second);
data[*datalen] = first;
@ -109,9 +108,21 @@ int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datal
if (verbose) PrintAndLog("timeout while waiting for reply.");
return 0;
}
*datalen = resp.arg[0];
if (verbose) PrintAndLog("received %u octets", *datalen);
if(*datalen<2) return 0;
int ret = resp.arg[0];
if (verbose) {
if (ret < 0) {
PrintAndLog("tag didn't respond");
} else if (ret == 0) {
PrintAndLog("received SOF only (maybe iCLASS/Picopass)");
} else {
PrintAndLog("received %u octets", ret);
}
}
*datalen = ret;
if (ret < 2) return 0;
memcpy(data, resp.d.asBytes, *datalen);
if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen));
@ -128,7 +139,8 @@ int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datal
return 1;
}
int CmdHF14BCmdRaw (const char *Cmd) {
static int CmdHF14BCmdRaw (const char *Cmd) {
bool reply = true;
bool crc = false;
bool power = false;
@ -139,7 +151,7 @@ int CmdHF14BCmdRaw (const char *Cmd) {
uint8_t datalen = 0;
unsigned int temp;
int i = 0;
if (strlen(Cmd)<3) {
if (strlen(Cmd) < 2) {
PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] [-s || -ss] <0A 0B 0C ... hex>");
PrintAndLog(" -r do not read response");
PrintAndLog(" -c calculate and append CRC");
@ -200,8 +212,7 @@ int CmdHF14BCmdRaw (const char *Cmd) {
PrintAndLog("Invalid char on input");
return 0;
}
if (datalen == 0)
{
if (datalen == 0) {
PrintAndLog("Missing data input");
return 0;
}
@ -224,10 +235,13 @@ int CmdHF14BCmdRaw (const char *Cmd) {
cmd2[2] = 0x08;
}
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b();
if ( SRx && (cmdLen != 3 || !crc2) ) return rawClose();
else if (cmd2[0] != 0x50 || cmdLen != 14 || !crc2) return rawClose();
if (SRx) {
if (cmdLen != 3 || !crc2) return switch_off_field_14b();
} else {
if (cmd2[0] != 0x50 || cmdLen != 14 || !crc2) return switch_off_field_14b();
}
uint8_t chipID = 0;
if (SRx) {
@ -247,14 +261,17 @@ int CmdHF14BCmdRaw (const char *Cmd) {
cmdLen = 9;
}
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b();
if (cmdLen != 3 || !crc2) return rawClose();
if (SRx && cmd2[0] != chipID) return rawClose();
if (cmdLen != 3 || !crc2) return switch_off_field_14b();
if (SRx && cmd2[0] != chipID) return switch_off_field_14b();
}
return HF14BCmdRaw(reply, &crc, power, data, &datalen, true);
}
// print full atqb info
static void print_atqb_resp(uint8_t *data) {
//PrintAndLog (" UID: %s", sprint_hex(data+1,4));
@ -305,24 +322,6 @@ static void print_atqb_resp(uint8_t *data){
return;
}
// get SRx chip model (from UID) // from ST Microelectronics
char *get_ST_Chip_Model(uint8_t data){
static char model[20];
char *retStr = model;
memset(model,0, sizeof(model));
switch (data) {
case 0x0: sprintf(retStr, "SRIX4K (Special)"); break;
case 0x2: sprintf(retStr, "SR176"); break;
case 0x3: sprintf(retStr, "SRIX4K"); break;
case 0x4: sprintf(retStr, "SRIX512"); break;
case 0x6: sprintf(retStr, "SRI512"); break;
case 0x7: sprintf(retStr, "SRI4K"); break;
case 0xC: sprintf(retStr, "SRT512"); break;
default : sprintf(retStr, "Unknown"); break;
}
return retStr;
}
int print_ST_Lock_info(uint8_t model) {
//assume connection open and tag selected...
@ -333,8 +332,8 @@ int print_ST_Lock_info(uint8_t model){
uint8_t blk1;
data[0] = 0x08;
if (model == 0x2) { //SR176 has special command:
data[1] = 0xf;
if (model == 0x02) { //SR176 has special command:
data[1] = 0x0f;
resplen = 4;
} else {
data[1] = 0xff;
@ -342,9 +341,9 @@ int print_ST_Lock_info(uint8_t model){
}
//std read cmd
if (HF14BCmdRaw(true, &crc, true, data, &datalen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) == 0) return switch_off_field_14b();
if (datalen != resplen || !crc) return rawClose();
if (datalen != resplen || !crc) return switch_off_field_14b();
PrintAndLog("Chip Write Protection Bits:");
// now interpret the data
@ -384,20 +383,22 @@ int print_ST_Lock_info(uint8_t model){
}
break;
default:
return rawClose();
return switch_off_field_14b();
}
return 1;
}
// print UID info from SRx chips (ST Microelectronics)
static void print_st_general_info(uint8_t *data) {
//uid = first 8 bytes in data
PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data, 8, 8), 8));
PrintAndLog(" MFG: %02X, %s", data[6], getTagInfo(data[6]));
PrintAndLog(" Chip: %02X, %s", data[5]>>2, get_ST_Chip_Model(data[5]>>2));
PrintAndLog(" MFG: %02X, %s", data[6], getManufacturerName(data[6]));
PrintAndLog(" Chip: %02X, %s", data[5], getChipInfo(data[6], data[5]));
return;
}
// 14b get and print UID only (general info)
int HF14BStdReader(uint8_t *data, uint8_t *datalen) {
//05 00 00 = find one tag in field
@ -424,9 +425,9 @@ int HF14BStdReader(uint8_t *data, uint8_t *datalen){
data[1] = 0x00;
data[2] = 0x08;
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b();
if (data[0] != 0x50 || *datalen != 14 || !crc) return rawClose();
if (data[0] != 0x50 || *datalen != 14 || !crc) return switch_off_field_14b();
PrintAndLog ("\n14443-3b tag found:");
PrintAndLog (" UID: %s", sprint_hex(data+1, 4));
@ -448,28 +449,29 @@ int HF14BStdReader(uint8_t *data, uint8_t *datalen){
cmdLen = 9;
// attrib
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b();
if (cmdLen != 3 || !crc2) return rawClose();
if (cmdLen != 3 || !crc2) return switch_off_field_14b();
// add attrib responce to data
data[14] = cmd2[0];
rawClose();
switch_off_field_14b();
return 1;
}
// 14b get and print Full Info (as much as we know)
int HF14BStdInfo(uint8_t *data, uint8_t *datalen){
if (!HF14BStdReader(data,datalen)) return 0;
static bool HF14B_Std_Info(uint8_t *data, uint8_t *datalen) {
if (!HF14BStdReader(data, datalen)) return false;
//add more info here
print_atqb_resp(data);
return 1;
return true;
}
// SRx get and print general info about SRx chip from UID
int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){
static bool HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){
bool crc = true;
*datalen = 2;
//wake cmd
@ -478,9 +480,9 @@ int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){
//leave power on
// verbose on for now for testing - turn off when functional
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b();
if (*datalen != 3 || !crc) return rawClose();
if (*datalen != 3 || !crc) return switch_off_field_14b();
uint8_t chipID = data[0];
// select
@ -489,115 +491,139 @@ int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){
*datalen = 2;
//leave power on
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b();
if (*datalen != 3 || !crc || data[0] != chipID) return rawClose();
if (*datalen != 3 || !crc || data[0] != chipID) return switch_off_field_14b();
// get uid
data[0] = 0x0B;
*datalen = 1;
//leave power on
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose();
if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b();
if (*datalen != 10 || !crc) return rawClose();
if (*datalen != 10 || !crc) return switch_off_field_14b();
//power off ?
if (closeCon) rawClose();
if (closeCon) switch_off_field_14b();
PrintAndLog("\n14443-3b ST tag found:");
print_st_general_info(data);
return 1;
}
// SRx get and print full info (needs more info...)
int HF14B_ST_Info(uint8_t *data, uint8_t *datalen){
if (!HF14B_ST_Reader(data, datalen, false)) return 0;
static bool HF14B_ST_Info(bool verbose) {
uint8_t data[100];
uint8_t datalen;
if (!HF14B_ST_Reader(data, &datalen, false)) return false;
//add locking bit information here.
if (print_ST_Lock_info(data[5] >> 2))
rawClose();
switch_off_field_14b();
return 1;
return true;
}
// test for other 14b type tags (mimic another reader - don't have tags to identify)
int HF14B_Other_Reader(uint8_t *data, uint8_t *datalen){
static bool HF14B_Other_Reader(uint8_t *data, bool verbose) {
uint8_t datalen;
bool crc = true;
*datalen = 4;
//std read cmd
data[0] = 0x00;
data[1] = 0x0b;
data[2] = 0x3f;
data[3] = 0x80;
datalen = 4;
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) {
if (*datalen > 2 || !crc) {
if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) {
if (datalen > 2 || !crc) {
PrintAndLog ("\n14443-3b tag found:");
PrintAndLog ("Unknown tag type answered to a 0x000b3f80 command ans:");
PrintAndLog ("%s",sprint_hex(data,*datalen));
rawClose();
return 1;
PrintAndLog ("Unknown tag type answered to a 0x000b3f80 command:");
PrintAndLog ("%s", sprint_hex(data, datalen));
switch_off_field_14b();
return true;
}
}
crc = false;
*datalen = 1;
datalen = 1;
data[0] = 0x0a;
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) {
if (*datalen > 0) {
if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) {
if (datalen > 0) {
PrintAndLog ("\n14443-3b tag found:");
PrintAndLog ("Unknown tag type answered to a 0x0A command ans:");
PrintAndLog ("%s",sprint_hex(data,*datalen));
rawClose();
return 1;
PrintAndLog ("Unknown tag type answered to a 0x0A command:");
PrintAndLog ("%s", sprint_hex(data, datalen));
switch_off_field_14b();
return true;
}
}
crc = false;
*datalen = 1;
datalen = 1;
data[0] = 0x0c;
if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) {
if (*datalen > 0) {
if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) {
if (datalen > 0) {
PrintAndLog ("\n14443-3b tag found:");
PrintAndLog ("Unknown tag type answered to a 0x0C command ans:");
PrintAndLog ("%s",sprint_hex(data,*datalen));
rawClose();
return 1;
PrintAndLog ("Unknown tag type answered to a 0x0C command:");
PrintAndLog ("%s", sprint_hex(data, datalen));
switch_off_field_14b();
return true;
}
}
rawClose();
switch_off_field_14b();
return false;
}
// get and print all info known about any known 14b tag
static int usage_hf_14b_info(void) {
PrintAndLogEx(NORMAL, "Usage: hf 14b info [h] [s]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " s silently");
PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " hf 14b info");
return 0;
}
// get and print all info known about any known 14b tag
int HF14BInfo(bool verbose){
int infoHF14B(bool verbose) {
uint8_t data[100];
uint8_t datalen = 5;
uint8_t datalen;
// try std 14b (atqb)
if (HF14BStdInfo(data, &datalen)) return 1;
if (HF14B_Std_Info(data, &datalen)) return 1;
// try st 14b
if (HF14B_ST_Info(data, &datalen)) return 1;
if (HF14B_ST_Info(verbose)) return 1;
// try unknown 14b read commands (to be identified later)
// could be read of calypso, CEPAS, moneo, or pico pass.
if (HF14B_Other_Reader(data, &datalen)) return 1;
if (HF14B_Other_Reader(data, verbose)) return 1;
if (verbose) PrintAndLog("no 14443B tag found");
return 0;
}
// menu command to get and print all info known about any known 14b tag
int CmdHF14Binfo(const char *Cmd){
return HF14BInfo(true);
static int CmdHF14Binfo(const char *Cmd){
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_hf_14b_info();
bool verbose = !(cmdp == 's');
return infoHF14B(verbose);
}
// get and print general info about all known 14b chips
int HF14BReader(bool verbose){
int readHF14B(bool verbose){
uint8_t data[100];
uint8_t datalen = 5;
@ -609,17 +635,34 @@ int HF14BReader(bool verbose){
// try unknown 14b read commands (to be identified later)
// could be read of calypso, CEPAS, moneo, or pico pass.
if (HF14B_Other_Reader(data, &datalen)) return 1;
if (HF14B_Other_Reader(data, verbose)) return 1;
if (verbose) PrintAndLog("no 14443B tag found");
return 0;
}
// menu command to get and print general info about all known 14b chips
int CmdHF14BReader(const char *Cmd){
return HF14BReader(true);
static int usage_hf_14b_reader(void) {
PrintAndLogEx(NORMAL, "Usage: hf 14b reader [h] [s]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " s silently");
PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " hf 14b reader");
return 0;
}
static int CmdHF14BReader(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_hf_14b_reader();
bool verbose = !(cmdp == 's');
return readHF14B(verbose);
}
int CmdSriWrite(const char *Cmd) {
/*
* For SRIX4K blocks 00 - 7F
@ -635,7 +678,6 @@ int CmdSriWrite( const char *Cmd){
uint8_t blockno = -1;
uint8_t data[4] = {0x00};
bool isSrix4k = true;
char str[20];
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {
PrintAndLog("Usage: hf 14b write <1|2> <BLOCK> <DATA>");
@ -681,12 +723,16 @@ int CmdSriWrite( const char *Cmd){
else
PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data, 4));
sprintf(str, "-c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]);
char str[22];
sprintf(str, "-ss -c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]);
CmdHF14BCmdRaw(str);
return 0;
}
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},

View file

@ -21,6 +21,6 @@ int CmdHF14BSnoop(const char *Cmd);
int CmdSri512Read(const char *Cmd);
int CmdSrix4kRead(const char *Cmd);
int CmdHF14BWrite( const char *cmd);
int HF14BInfo(bool verbose);
int infoHF14B(bool verbose);
#endif

View file

@ -35,175 +35,63 @@
#include "util.h"
#include "cmdparser.h"
#include "iso15693tools.h"
#include "protocols.h"
#include "cmdmain.h"
#define FrameSOF Iso15693FrameSOF
#define Logic0 Iso15693Logic0
#define Logic1 Iso15693Logic1
#define FrameEOF Iso15693FrameEOF
#include "taginfo.h"
#define Crc(data,datalen) Iso15693Crc(data,datalen)
#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen)
#define sprintUID(target,uid) Iso15693sprintUID(target,uid)
// structure and database for uid -> tagtype lookups
typedef struct {
uint64_t uid;
int mask; // how many MSB bits used
char* desc;
} productName;
// SOF defined as
// 1) Unmodulated time of 56.64us
// 2) 24 pulses of 423.75khz
// 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz)
static const int Iso15693FrameSOF[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, -1, -1, -1,
-1, -1, -1, -1,
1, 1, 1, 1,
1, 1, 1, 1
};
static const int Iso15693Logic0[] = {
1, 1, 1, 1,
1, 1, 1, 1,
-1, -1, -1, -1,
-1, -1, -1, -1
};
static const int Iso15693Logic1[] = {
-1, -1, -1, -1,
-1, -1, -1, -1,
1, 1, 1, 1,
1, 1, 1, 1
};
const productName uidmapping[] = {
// EOF defined as
// 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us)
// 2) 24 pulses of 423.75khz
// 3) Unmodulated time of 56.64us
// UID, #significant Bits, "Vendor(+Product)"
{ 0xE001000000000000LL, 16, "Motorola UK" },
// E0 02 xx
// 02 = ST Microelectronics
// XX = IC id (Chip ID Family)
{ 0xE002000000000000LL, 16, "ST Microelectronics SA France" },
{ 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"},
{ 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"},
{ 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"},
{ 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"},
{ 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" },
// E0 04 xx
// 04 = Manufacturer code (Philips/NXP)
// XX = IC id (Chip ID Family)
//I-Code SLI SL2 ICS20 [IC id = 01]
//I-Code SLI-S [IC id = 02]
//I-Code SLI-L [IC id = 03]
//I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)]
//I-Code SLIX-S [IC id = 02 + bit36 set to 1]
//I-Code SLIX-L [IC id = 03 + bit36 set to 1]
{ 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" },
{ 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" },
{ 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" },
{ 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" },
// E0 05 XX .. .. ..
// 05 = Manufacturer code (Infineon)
// XX = IC id (Chip ID Family)
{ 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" },
{ 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"},
{ 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"},
{ 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"},
{ 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"},
{ 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"},
{ 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"},
{ 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"},
{ 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"},
{ 0xE006000000000000LL, 16, "Cylink USA" },
// E0 07 xx
// 07 = Texas Instruments
// XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family)
//Tag IT RFIDType-I Plus, 2kBit, TI Inlay
//Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit
//Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit
//Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit
//Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection
{ 0xE007000000000000LL, 16, "Texas Instrument France" },
{ 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" },
{ 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" },
{ 0xE007800000000000LL, 23, "Texas Instrument; Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" },
{ 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" },
{ 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" },
{ 0xE008000000000000LL, 16, "Fujitsu Limited Japan" },
{ 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" },
{ 0xE00A000000000000LL, 16, "NEC Japan" },
{ 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" },
{ 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" },
{ 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" },
{ 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" },
{ 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" },
{ 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" },
{ 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" },
{ 0xE012000000000000LL, 16, "HID Corporation" },
{ 0xE012000000000000LL, 16, "INSIDE Technology France" },
{ 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" },
{ 0xE014000000000000LL, 16, "SHARP Corporation Japan" },
{ 0xE015000000000000LL, 16, "ATMEL France" },
{ 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)"},
{ 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034 [IC id = 01] (Read/Write - no AFI)"},
{ 0xE0160C0000000000LL, 24, "EM-Marin SA (Skidata); EM4035 [IC id = 03] (Read/Write - replaced by 4233)"},
{ 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"},
{ 0xE016140000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 05] 28pF"},
{ 0xE016180000000000LL, 24, "EM-Marin SA (Skidata); EM4006 [IC id = 06] (Read Only)"},
{ 0xE0161C0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 07] 23,5pF (Read/Write)"},
{ 0xE016200000000000LL, 24, "EM-Marin SA (Skidata); EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"},
{ 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"},
{ 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" },
{ 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"},
{ 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"},
{ 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "},
{ 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" },
{ 0xE016A80000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 42] 97pF" },
{ 0xE016BC0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 47] 97pF" },
{ 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" },
{ 0xE018000000000000LL, 16, "ZMD AG Germany" },
{ 0xE019000000000000LL, 16, "XICOR, Inc. USA" },
{ 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" },
{ 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" },
{ 0xE01C000000000000LL, 16, "Emosyn USA" },
{ 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" },
{ 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" },
{ 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" },
{ 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" },
{ 0xE021000000000000LL, 16, "TAGSYS France" },
{ 0xE022000000000000LL, 16, "Transcore USA" },
{ 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" },
{ 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" },
{ 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" },
{ 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" },
{ 0xE027000000000000LL, 16, "Cypak AB Sweden" },
{ 0xE028000000000000LL, 16, "Ricoh Japan" },
{ 0xE029000000000000LL, 16, "ASK France" },
{ 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" },
{ 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" },
{ 0xE02C000000000000LL, 16, "Impinj, Inc. USA" },
{ 0xE02D000000000000LL, 16, "RightPlug Alliance USA" },
{ 0xE02E000000000000LL, 16, "Broadcom Corporation USA" },
{ 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" },
{ 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" },
{ 0xE031000000000000LL, 16, " RFIDsec Denmark" },
{ 0xE032000000000000LL, 16, " Schweizer Electronic AG Germany" },
{ 0xE033000000000000LL, 16, " AMIC Technology Corp Taiwan" },
{ 0xE034000000000000LL, 16, "Mikron JSC Russia" },
{ 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" },
{ 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" },
{ 0xE037000000000000LL, 16, "Kovio USA" },
{ 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" },
{ 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" },
{ 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" },
{ 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" },
{ 0xE03C000000000000LL, 16, "Verayo Inc. USA" },
{ 0xE03D000000000000LL, 16, "HID Global USA" },
{ 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" },
{ 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" },
{ 0xE040000000000000LL, 16, "Gemalto SA France" },
{ 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" },
{ 0xE042000000000000LL, 16, "3Alogics Inc Korea" },
{ 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" },
{ 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" },
{ 0,0,"no tag-info available" } // must be the last entry
static const int Iso15693FrameEOF[] = {
1, 1, 1, 1,
1, 1, 1, 1,
-1, -1, -1, -1,
-1, -1, -1, -1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
// fast method to just read the UID of a tag (collission detection not supported)
// *buf should be large enough to fit the 64bit uid
// returns 1 if suceeded
int getUID(uint8_t *buf)
{
// returns true if suceeded
static bool getUID(uint8_t *buf) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
@ -211,10 +99,8 @@ int getUID(uint8_t *buf)
int reqlen=0;
for (int retry = 0;retry < 3; retry++) { // don't give up the at the first try
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
req[1]=ISO15_CMD_INVENTORY;
req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1;
req[1] = ISO15693_INVENTORY;
req[2] = 0; // mask length
reqlen = AddCrc(req, 3);
c.arg[0] = reqlen;
@ -223,41 +109,13 @@ int getUID(uint8_t *buf)
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
recv = resp.d.asBytes;
if (resp.arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) {
if (resp.arg[0] >= 12 && ISO15693_CRC_CHECK == Crc(recv, 12)) {
memcpy(buf, &recv[2], 8);
return 1;
return true;
}
}
} // retry
return 0;
}
// get a product description based on the UID
// uid[8] tag uid
// returns description of the best match
static char* getTagInfo(uint8_t *uid) {
uint64_t myuid,mask;
int i=0, best=-1;
memcpy(&myuid,uid,sizeof(uint64_t));
while (uidmapping[i].mask>0) {
mask=(~0LL) <<(64-uidmapping[i].mask);
if ((myuid & mask) == uidmapping[i].uid) {
if (best==-1) {
best=i;
} else {
if (uidmapping[i].mask>uidmapping[best].mask) {
best=i;
}
}
}
i++;
}
if (best>=0) return uidmapping[best].desc;
return uidmapping[i].desc;
return false;
}
@ -279,8 +137,7 @@ static char* TagErrorStr(uint8_t error) {
// Mode 3
int CmdHF15Demod(const char *Cmd)
{
static int CmdHF15Demod(const char *Cmd) {
// The sampling rate is 106.353 ksps/s, for T = 18.8 us
int i, j;
@ -293,8 +150,8 @@ int CmdHF15Demod(const char *Cmd)
// First, correlate for SOF
for (i = 0; i < 200; i++) {
int corr = 0;
for (j = 0; j < arraylen(FrameSOF); j += skip) {
corr += FrameSOF[j] * GraphBuffer[i + (j / skip)];
for (j = 0; j < arraylen(Iso15693FrameSOF); j += skip) {
corr += Iso15693FrameSOF[j] * GraphBuffer[i + (j / skip)];
}
if (corr > max) {
max = corr;
@ -302,28 +159,28 @@ int CmdHF15Demod(const char *Cmd)
}
}
PrintAndLog("SOF at %d, correlation %d", maxPos,
max / (arraylen(FrameSOF) / skip));
max / (arraylen(Iso15693FrameSOF) / skip));
i = maxPos + arraylen(FrameSOF) / skip;
i = maxPos + arraylen(Iso15693FrameSOF) / skip;
int k = 0;
uint8_t outBuf[20];
memset(outBuf, 0, sizeof(outBuf));
uint8_t mask = 0x01;
for (;;) {
int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0;
for(j = 0; j < arraylen(Logic0); j += skip) {
corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];
for(j = 0; j < arraylen(Iso15693Logic0); j += skip) {
corr0 += Iso15693Logic0[j]*GraphBuffer[i+(j/skip)];
}
corr01 = corr00 = corr0;
for(j = 0; j < arraylen(Logic0); j += skip) {
corr00 += Logic0[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
corr01 += Logic1[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
for(j = 0; j < arraylen(Iso15693Logic0); j += skip) {
corr00 += Iso15693Logic0[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)];
corr01 += Iso15693Logic1[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)];
}
for(j = 0; j < arraylen(Logic1); j += skip) {
corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];
for(j = 0; j < arraylen(Iso15693Logic1); j += skip) {
corr1 += Iso15693Logic1[j]*GraphBuffer[i+(j/skip)];
}
for(j = 0; j < arraylen(FrameEOF); j += skip) {
corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];
for(j = 0; j < arraylen(Iso15693FrameEOF); j += skip) {
corrEOF += Iso15693FrameEOF[j]*GraphBuffer[i+(j/skip)];
}
// Even things out by the length of the target waveform.
corr00 *= 2;
@ -335,17 +192,17 @@ int CmdHF15Demod(const char *Cmd)
PrintAndLog("EOF at %d", i);
break;
} else if (corr1 > corr0) {
i += arraylen(Logic1) / skip;
i += arraylen(Iso15693Logic1) / skip;
outBuf[k] |= mask;
} else {
i += arraylen(Logic0) / skip;
i += arraylen(Iso15693Logic0) / skip;
}
mask <<= 1;
if (mask == 0) {
k++;
mask = 0x01;
}
if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) {
if ((i + (int)arraylen(Iso15693FrameEOF)) >= GraphTraceLen) {
PrintAndLog("ran off end!");
break;
}
@ -364,26 +221,23 @@ int CmdHF15Demod(const char *Cmd)
}
// * Acquire Samples as Reader (enables carrier, sends inquiry)
int CmdHF15Read(const char *Cmd)
{
static int CmdHF15Read(const char *Cmd) {
UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693};
SendCommand(&c);
return 0;
}
// Record Activity without enabling carrier
// TODO: currently it DOES enable the carrier
int CmdHF15Record(const char *Cmd)
{
UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693};
static int CmdHF15Snoop(const char *Cmd) {
UsbCommand c = {CMD_SNOOP_ISO_15693};
SendCommand(&c);
return 0;
}
int HF15Reader(const char *Cmd, bool verbose)
{
int HF15Reader(const char *Cmd, bool verbose) {
uint8_t uid[8];
if (!getUID(uid)) {
@ -391,21 +245,22 @@ int HF15Reader(const char *Cmd, bool verbose)
return 0;
}
PrintAndLog("Tag UID : %s",sprintUID(NULL,uid));
PrintAndLog("Tag Info: %s",getTagInfo(uid));
PrintAndLog("UID: %s", sprintUID(NULL,uid));
PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6]));
PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5]));
return 1;
}
int CmdHF15Reader(const char *Cmd)
{
static int CmdHF15Reader(const char *Cmd) {
UsbCommand c = {CMD_READER_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}};
SendCommand(&c);
return 0;
}
// Simulation is still not working very good
int CmdHF15Sim(const char *Cmd)
{
static int CmdHF15Sim(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
uint8_t uid[8] = {0x00};
@ -424,6 +279,7 @@ int CmdHF15Sim(const char *Cmd)
PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X",
uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]);
PrintAndLog("Press the button to stop simulation");
UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}};
memcpy(c.d.asBytes,uid,8);
@ -432,17 +288,18 @@ int CmdHF15Sim(const char *Cmd)
return 0;
}
// finds the AFI (Application Family Idendifier) of a card, by trying all values
// (There is no standard way of reading the AFI, allthough some tags support this)
int CmdHF15Afi(const char *Cmd)
{
static int CmdHF15Afi(const char *Cmd) {
UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}};
SendCommand(&c);
return 0;
}
// Reads all memory pages
int CmdHF15DumpMem(const char*Cmd) {
static int CmdHF15DumpMem(const char*Cmd) {
UsbCommand resp;
uint8_t uid[8];
uint8_t *recv=NULL;
@ -457,14 +314,15 @@ int CmdHF15DumpMem(const char*Cmd) {
return 0;
}
PrintAndLog("Reading memory from tag UID=%s",sprintUID(NULL,uid));
PrintAndLog("Tag Info: %s",getTagInfo(uid));
PrintAndLog("Reading memory from tag");
PrintAndLog("UID: %s", sprintUID(NULL,uid));
PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6]));
PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5]));
for (int retry=0; retry<5; retry++) {
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[1]=ISO15_CMD_READ;
req[0]= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
req[1] = ISO15693_READBLOCK;
memcpy(&req[2],uid,8);
req[10] = blocknum;
reqlen = AddCrc(req,11);
@ -474,8 +332,8 @@ int CmdHF15DumpMem(const char*Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
retry=0;
*output=0; // reset outputstring
sprintf(output, "Block %02x ",blocknum);
@ -499,7 +357,7 @@ int CmdHF15DumpMem(const char*Cmd) {
// TODO: need fix
// if (resp.arg[0]<3)
// PrintAndLog("Lost Connection");
// else if (ISO15_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0]))
// else if (ISO15693_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0]))
// PrintAndLog("CRC Failed");
// else
// PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
@ -507,49 +365,15 @@ int CmdHF15DumpMem(const char*Cmd) {
}
// "HF 15" interface
static command_t CommandTable15[] =
{
{"help", CmdHF15Help, 1, "This help"},
{"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"},
{"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"},
{"record", CmdHF15Record, 0, "Record Samples (ISO 15693)"}, // atrox
{"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"},
{"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"},
{"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"},
{"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"},
{"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"},
{NULL, NULL, 0, NULL}
};
int CmdHF15(const char *Cmd)
{
CmdsParse(CommandTable15, Cmd);
return 0;
}
int CmdHF15Help(const char *Cmd)
{
CmdsHelp(CommandTable15);
return 0;
}
// "HF 15 Cmd" Interface
// Allows direct communication with the tag on command level
int CmdHF15CmdInquiry(const char *Cmd)
{
static int CmdHF15CmdInquiry(const char *Cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
uint8_t *req=c.d.asBytes;
int reqlen=0;
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
req[1]=ISO15_CMD_INVENTORY;
req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1;
req[1] = ISO15693_INVENTORY;
req[2] = 0; // mask length
reqlen=AddCrc(req,3);
c.arg[0] = reqlen;
@ -559,8 +383,9 @@ int CmdHF15CmdInquiry(const char *Cmd)
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
if (resp.arg[0]>=12) {
recv = resp.d.asBytes;
PrintAndLog("UID=%s",sprintUID(NULL,&recv[2]));
PrintAndLog("Tag Info: %s",getTagInfo(&recv[2]));
PrintAndLog("UID: %s", sprintUID(NULL,recv+2));
PrintAndLog("Manufacturer byte: %02X, %s", recv[8], getManufacturerName(recv[8]));
PrintAndLog("Chip ID: %02X, %s", recv[7], getChipInfo(recv[8], recv[7]));
} else {
PrintAndLog("Response to short, just %i bytes. No tag?\n",resp.arg[0]);
}
@ -572,7 +397,7 @@ int CmdHF15CmdInquiry(const char *Cmd)
// Turns debugging on(1)/off(0)
int CmdHF15CmdDebug( const char *cmd) {
static int CmdHF15CmdDebug( const char *cmd) {
int debug = atoi(cmd);
if (strlen(cmd) < 1) {
PrintAndLog("Usage: hf 15 debug <0|1>");
@ -587,7 +412,7 @@ int CmdHF15CmdDebug( const char *cmd) {
}
int CmdHF15CmdRaw (const char *cmd) {
static int CmdHF15CmdRaw (const char *cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
@ -601,7 +426,7 @@ int CmdHF15CmdRaw (const char *cmd) {
char *hexout;
if (strlen(cmd)<3) {
if (strlen(cmd)<2) {
PrintAndLog("Usage: hf 15 cmd raw [-r] [-2] [-c] <0A 0B 0C ... hex>");
PrintAndLog(" -r do not read response");
PrintAndLog(" -2 use slower '1 out of 256' mode");
@ -665,7 +490,11 @@ int CmdHF15CmdRaw (const char *cmd) {
if (reply) {
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
recv = resp.d.asBytes;
PrintAndLog("received %i octets",resp.arg[0]);
int recv_len = resp.arg[0];
if (recv_len == 0) {
PrintAndLog("received SOF only. Maybe Picopass/iCLASS?");
} else if (recv_len > 0) {
PrintAndLog("received %i octets", recv_len);
hexout = (char *)malloc(resp.arg[0] * 3 + 1);
if (hexout != NULL) {
for (int i = 0; i < resp.arg[0]; i++) { // data in hex
@ -674,11 +503,16 @@ int CmdHF15CmdRaw (const char *cmd) {
PrintAndLog("%s", hexout);
free(hexout);
}
} else if (recv_len == -1) {
PrintAndLog("card didn't respond");
} else if (recv_len == -2) {
PrintAndLog("receive buffer overflow");
}
} else {
PrintAndLog("timeout while waiting for reply.");
}
}
} // if reply
return 0;
}
@ -688,7 +522,7 @@ int CmdHF15CmdRaw (const char *cmd) {
* Parameters:
* **cmd command line
*/
int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
static int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
int temp;
uint8_t *req = c->d.asBytes;
uint8_t uid[8] = {0x00};
@ -706,7 +540,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
while (**cmd == ' ' || **cmd == '\t') (*cmd)++;
if (strstr(*cmd, "-o") == *cmd) {
req[reqlen]=ISO15_REQ_OPTION;
req[reqlen] = ISO15693_REQ_OPTION;
(*cmd) += 2;
}
@ -721,23 +555,20 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
case 's':
case 'S':
// you must have selected the tag earlier
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_SELECT;
memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen);
reqlen += iso15cmdlen;
break;
case 'u':
case 'U':
// unaddressed mode may not be supported by all vendors
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH;
memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen);
reqlen += iso15cmdlen;
break;
case '*':
// we scan for the UID ourself
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen);
reqlen += iso15cmdlen;
if (!getUID(uid)) {
@ -749,8 +580,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
reqlen += 8;
break;
default:
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen);
reqlen += iso15cmdlen;
@ -781,7 +611,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
* Commandline handling: HF15 CMD SYSINFO
* get system information from tag/VICC
*/
int CmdHF15CmdSysinfo(const char *Cmd) {
static int CmdHF15CmdSysinfo(const char *Cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
@ -809,7 +639,7 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_GET_SYSTEM_INFO},1);
reqlen=c.arg[0];
reqlen=AddCrc(req,reqlen);
@ -819,18 +649,12 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000) && resp.arg[0] > 2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK == Crc(recv, resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
for ( i=1; i<resp.arg[0]-2; i++) {
sprintf(output+strlen(output),"%02X ",recv[i]);
}
strcat(output,"\n\r");
strcat(output,"UID = ");
strcat(output,sprintUID(NULL,recv+2));
strcat(output,"\n\r");
strcat(output,getTagInfo(recv+2)); //ABC
strcat(output,"\n\r");
PrintAndLog("UID: %s", sprintUID(NULL,recv+2));
PrintAndLog("Manufacturer byte: %02X, %s", recv[8], getManufacturerName(recv[8]));
PrintAndLog("Chip ID: %02X, %s", recv[7], getChipInfo(recv[8], recv[7]));
i=10;
if (recv[1] & 0x01)
sprintf(output+strlen(output),"DSFID supported, set to %02X\n\r",recv[i++]);
@ -865,11 +689,12 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
return 0;
}
/**
* Commandline handling: HF15 CMD READMULTI
* Read multiple blocks at once (not all tags support this)
*/
int CmdHF15CmdReadmulti(const char *Cmd) {
static int CmdHF15CmdReadmulti(const char *Cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
@ -896,7 +721,7 @@ int CmdHF15CmdReadmulti(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READMULTI},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_READ_MULTI_BLOCK},1);
reqlen=c.arg[0];
pagenum=strtol(cmd,NULL,0);
@ -920,8 +745,8 @@ int CmdHF15CmdReadmulti(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
for ( int i=1; i<resp.arg[0]-2; i++) {
sprintf(output+strlen(output),"%02X ",recv[i]);
@ -944,11 +769,12 @@ int CmdHF15CmdReadmulti(const char *Cmd) {
return 0;
}
/**
* Commandline handling: HF15 CMD READ
* Reads a single Block
*/
int CmdHF15CmdRead(const char *Cmd) {
static int CmdHF15CmdRead(const char *Cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
@ -974,7 +800,7 @@ int CmdHF15CmdRead(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READ},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_READBLOCK},1);
reqlen=c.arg[0];
pagenum=strtol(cmd,NULL,0);
@ -993,8 +819,8 @@ int CmdHF15CmdRead(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
//sprintf(output, "Block %2i ",blocknum);
for ( int i=1; i<resp.arg[0]-2; i++) {
@ -1021,12 +847,11 @@ int CmdHF15CmdRead(const char *Cmd) {
/**
* Commandline handling: HF15 CMD WRITE
* Writes a single Block - might run into timeout, even when successful
*/
int CmdHF15CmdWrite(const char *Cmd) {
* Writes a single Block
**/
static int CmdHF15CmdWrite(const char *Cmd) {
UsbCommand resp;
uint8_t *recv;
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len, speed, recv
uint8_t *req = c.d.asBytes;
int reqlen = 0, pagenum, temp;
char cmdbuf[100];
@ -1051,7 +876,7 @@ int CmdHF15CmdWrite(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_WRITE},1);
prepareHF15Cmd(&cmd, &c, (uint8_t[]){ISO15693_WRITEBLOCK}, 1);
reqlen = c.arg[0];
// *cmd -> page num ; *cmd2 -> data
@ -1079,33 +904,124 @@ int CmdHF15CmdWrite(const char *Cmd) {
}
reqlen = AddCrc(req, reqlen);
c.arg[0] = reqlen;
SendCommand(&c);
if (WaitForResponseTimeout(CMD_ACK,&resp,2000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
PrintAndLog("OK");
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
int recv_len = resp.arg[0];
uint8_t *recv = resp.d.asBytes;
if (recv_len == 0) {
PrintAndLog("Received SOF only. Maybe Picopass/iCLASS?");
} else if (recv_len == -1) {
PrintAndLog("Tag didn't respond");
} else if (recv_len == -2) {
PrintAndLog("Receive buffer overflow");
} else if (ISO15693_CRC_CHECK != Crc(recv, resp.arg[0])) {
PrintAndLog("CRC check failed on Tag response");
} else if (!(recv[0] & ISO15693_RES_ERROR)) {
PrintAndLog("Tag returned OK");
} else {
PrintAndLog("Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1]));
}
} else {
PrintAndLog("CRC failed");
}
} else {
PrintAndLog("timeout: no answer - data may be written anyway");
PrintAndLog("No answer from Proxmark");
}
return 0;
}
static int CmdHF15CSetUID(const char *Cmd) {
uint8_t uid[8] = {0x00};
uint8_t oldUid[8], newUid[8] = {0x00};
static command_t CommandTable15Cmd[] =
{
uint8_t needHelp = 0;
char cmdp = 1;
if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 16)) {
PrintAndLog("UID must include 16 HEX symbols");
return 1;
}
if (uid[0] != 0xe0) {
PrintAndLog("UID must begin with the byte 'E0'");
return 1;
}
while (param_getchar(Cmd, cmdp) != 0x00) {
switch (param_getchar(Cmd, cmdp)) {
case 'h':
case 'H':
needHelp = 1;
break;
default:
PrintAndLog("ERROR: Unknown parameter '%c'", param_getchar(Cmd, cmdp));
needHelp = 1;
break;
}
cmdp++;
}
if (strlen(Cmd) < 1 || needHelp) {
PrintAndLog("");
PrintAndLog("Usage: hf 15 csetuid <UID 16 hex symbols>");
PrintAndLog("sample: hf 15 csetuid E004013344556677");
PrintAndLog("Set UID for magic Chinese card (only works with such cards)");
return 0;
}
PrintAndLog("Using backdoor Magic tag function");
if (!getUID(oldUid)) {
PrintAndLog("Can't get old UID.");
return 1;
}
UsbCommand c = {CMD_CSETUID_ISO_15693, {0, 0, 0}};
memcpy(c.d.asBytes, uid, 8);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
int recv_len = resp.arg[0];
uint8_t *recv = resp.d.asBytes;
if (recv_len == 0) {
PrintAndLog("Received SOF only. Maybe Picopass/iCLASS?");
} else if (recv_len == -1) {
PrintAndLog("Tag didn't respond");
} else if (recv_len == -2) {
PrintAndLog("Receive buffer overflow");
} else if (ISO15693_CRC_CHECK != Crc(recv, recv_len)) {
PrintAndLog("CRC check failed on Tag response");
} else if (!(recv[0] & ISO15693_RES_ERROR)) {
PrintAndLog("Tag returned OK");
} else {
PrintAndLog("Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1]));
}
} else {
PrintAndLog("No answer from Proxmark");
}
if (!getUID(newUid)) {
PrintAndLog("Can't get new UID.");
return 1;
}
PrintAndLog("");
PrintAndLog("old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]);
PrintAndLog("new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]);
return 0;
}
// "HF 15 Cmd" Interface
// Allows direct communication with the tag on command level
static int CmdHF15CmdHelp(const char*Cmd);
static command_t CommandTable15Cmd[] = {
{"help", CmdHF15CmdHelp, 1, "This Help"},
{"inquiry", CmdHF15CmdInquiry, 0, "Search for tags in range"},
/*
@ -1120,15 +1036,47 @@ static command_t CommandTable15Cmd[] =
{NULL, NULL, 0, NULL}
};
int CmdHF15Cmd(const char *Cmd)
{
static int CmdHF15Cmd(const char *Cmd) {
CmdsParse(CommandTable15Cmd, Cmd);
return 0;
}
int CmdHF15CmdHelp(const char *Cmd)
{
static int CmdHF15CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable15Cmd);
return 0;
}
// "HF 15" interface
static int CmdHF15Help(const char*Cmd);
static command_t CommandTable15[] = {
{"help", CmdHF15Help, 1, "This help"},
{"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"},
{"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"},
{"snoop", CmdHF15Snoop, 0, "Eavesdrop ISO 15693 communications"},
{"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"},
{"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"},
{"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"},
{"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"},
{"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"},
{"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"},
{NULL, NULL, 0, NULL}
};
int CmdHF15(const char *Cmd) {
CmdsParse(CommandTable15, Cmd);
return 0;
}
static int CmdHF15Help(const char *Cmd) {
CmdsHelp(CommandTable15);
return 0;
}

View file

@ -13,16 +13,7 @@
#include <stdbool.h>
int CmdHF15(const char *Cmd);
int CmdHF15Demod(const char *Cmd);
int CmdHF15Read(const char *Cmd);
int HF15Reader(const char *Cmd, bool verbose);
int CmdHF15Reader(const char *Cmd);
int CmdHF15Sim(const char *Cmd);
int CmdHF15Record(const char *Cmd);
int CmdHF15Cmd(const char*Cmd);
int CmdHF15CmdHelp(const char*Cmd);
int CmdHF15Help(const char*Cmd);
extern int CmdHF15(const char *Cmd);
extern int HF15Reader(const char *Cmd, bool verbose);
#endif

926
client/cmdhffido.c Normal file
View file

@ -0,0 +1,926 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Plus commands
//-----------------------------------------------------------------------------
//
// Documentation here:
//
// FIDO Alliance specifications
// https://fidoalliance.org/download/
// FIDO NFC Protocol Specification v1.0
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html
// FIDO U2F Raw Message Formats
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html
//-----------------------------------------------------------------------------
#include "cmdhffido.h"
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <jansson.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/x509.h>
#include <mbedtls/pk.h>
#include "comms.h"
#include "cmdmain.h"
#include "util.h"
#include "ui.h"
#include "proxmark3.h"
#include "mifare.h"
#include "emv/emvcore.h"
#include "emv/emvjson.h"
#include "emv/dump.h"
#include "emv/apduinfo.h"
#include "cliparser/cliparser.h"
#include "crypto/asn1utils.h"
#include "crypto/libpcrypto.h"
#include "fido/cbortools.h"
#include "fido/fidocore.h"
#include "fido/cose.h"
static int CmdHelp(const char *Cmd);
int CmdHFFidoInfo(const char *cmd) {
if (cmd && strlen(cmd) > 0)
PrintAndLog("WARNING: command don't have any parameters.\n");
// info about 14a part
CmdHF14AInfo("");
// FIDO info
PrintAndLog("--------------------------------------------");
SetAPDULogging(false);
uint8_t buf[APDU_RESPONSE_LEN] = {0};
size_t len = 0;
uint16_t sw = 0;
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
DropField();
return res;
}
if (sw != 0x9000) {
if (sw)
PrintAndLog("Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
else
PrintAndLog("APDU exchange error. Card returns 0x0000.");
DropField();
return 0;
}
if (!strncmp((char *)buf, "U2F_V2", 7)) {
if (!strncmp((char *)buf, "FIDO_2_0", 8)) {
PrintAndLog("FIDO2 authenricator detected. Version: %.*s", len, buf);
} else {
PrintAndLog("FIDO authenricator detected (not standard U2F).");
PrintAndLog("Non U2F authenticator version:");
dump_buffer((const unsigned char *)buf, len, NULL, 0);
}
} else {
PrintAndLog("FIDO U2F authenricator detected. Version: %.*s", len, buf);
}
res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw);
DropField();
if (res) {
return res;
}
if (sw != 0x9000) {
PrintAndLog("FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 0;
}
if(buf[0]) {
PrintAndLog("FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
return 0;
}
if (len > 1) {
// if (false) {
// PrintAndLog("FIDO2 version: (len=%d)", len);
// dump_buffer((const unsigned char *)buf, len, NULL, 0);
// }
PrintAndLog("FIDO2 version CBOR decoded:");
TinyCborPrintFIDOPackage(fido2CmdGetInfo, true, &buf[1], len - 1);
} else {
PrintAndLog("FIDO2 version length error");
}
return 0;
}
json_t *OpenJson(int paramnum, char *fname, void* argtable[], bool *err) {
json_t *root = NULL;
json_error_t error;
*err = false;
uint8_t jsonname[250] ={0};
char *cjsonname = (char *)jsonname;
int jsonnamelen = 0;
// CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen);
if (CLIParamStrToBuf(arg_get_str(paramnum), jsonname, sizeof(jsonname), &jsonnamelen)) {
CLIParserFree();
return NULL;
}
// current path + file name
if (!strstr(cjsonname, ".json"))
strcat(cjsonname, ".json");
if (jsonnamelen) {
strcpy(fname, get_my_executable_directory());
strcat(fname, cjsonname);
if (access(fname, F_OK) != -1) {
root = json_load_file(fname, 0, &error);
if (!root) {
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
*err = true;
return NULL;
}
if (!json_is_object(root)) {
PrintAndLog("ERROR: Invalid json format. root must be an object.");
json_decref(root);
*err = true;
return NULL;
}
} else {
root = json_object();
}
}
return root;
}
int CmdHFFidoRegister(const char *cmd) {
uint8_t data[64] = {0};
int chlen = 0;
uint8_t cdata[250] = {0};
int applen = 0;
uint8_t adata[250] = {0};
json_t *root = NULL;
CLIParserInit("hf fido reg",
"Initiate a U2F token registration. Needs two 32-byte hash number. \nchallenge parameter (32b) and application parameter (32b).",
"Usage:\n\thf fido reg -> execute command with 2 parameters, filled 0x00\n"
"\thf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"
"\thf fido reg -p s0 s1 -> execute command with plain parameters");
void* argtable[] = {
arg_param_begin,
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"),
arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool APDULogging = arg_get_lit(1);
bool verbose = arg_get_lit(2);
bool verbose2 = arg_get_lit(2) > 1;
bool paramsPlain = arg_get_lit(3);
bool showDERTLV = arg_get_lit(4);
char fname[250] = {0};
bool err;
root = OpenJson(5, fname, argtable, &err);
if(err)
return 1;
if (root) {
size_t jlen;
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
}
if (paramsPlain) {
memset(cdata, 0x00, 32);
CLIGetStrWithReturn(6, cdata, &chlen);
if (chlen && chlen > 16) {
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
return 1;
}
} else {
CLIGetHexWithReturn(6, cdata, &chlen);
if (chlen && chlen != 32) {
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
return 1;
}
}
if (chlen)
memmove(data, cdata, 32);
if (paramsPlain) {
memset(adata, 0x00, 32);
CLIGetStrWithReturn(7, adata, &applen);
if (applen && applen > 16) {
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
return 1;
}
} else {
CLIGetHexWithReturn(7, adata, &applen);
if (applen && applen != 32) {
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
return 1;
}
}
if (applen)
memmove(&data[32], adata, 32);
CLIParserFree();
SetAPDULogging(APDULogging);
// challenge parameter [32 bytes] - The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares
// application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity
uint8_t buf[2048] = {0};
size_t len = 0;
uint16_t sw = 0;
DropField();
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
DropField();
return res;
}
if (sw != 0x9000) {
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return 2;
}
res = FIDORegister(data, buf, sizeof(buf), &len, &sw);
DropField();
if (res) {
PrintAndLog("Can't execute register command. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 3;
}
PrintAndLog("");
if (APDULogging)
PrintAndLog("---------------------------------------------------------------");
PrintAndLog("data len: %d", len);
if (verbose2) {
PrintAndLog("--------------data----------------------");
dump_buffer((const unsigned char *)buf, len, NULL, 0);
PrintAndLog("--------------data----------------------");
}
if (buf[0] != 0x05) {
PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]);
return 5;
}
PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65));
uint8_t keyHandleLen = buf[66];
PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen));
int derp = 67 + keyHandleLen;
int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
if (verbose2) {
PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL);
PrintAndLog("\n----------------DER---------------------");
} else {
if (verbose)
PrintAndLog("------------------DER-------------------");
PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
}
// check and print DER certificate
uint8_t public_key[65] = {0};
// print DER certificate in TLV view
if (showDERTLV) {
PrintAndLog("----------------DER TLV-----------------");
asn1_print(&buf[derp], derLen, " ");
PrintAndLog("----------------DER TLV-----------------");
}
FIDOCheckDERAndGetKey(&buf[derp], derLen, verbose, public_key, sizeof(public_key));
// get hash
int hashp = 1 + 65 + 1 + keyHandleLen + derLen;
PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
// check ANSI X9.62 format ECDSA signature (on P-256)
uint8_t rval[300] = {0};
uint8_t sval[300] = {0};
res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval);
if (!res) {
if (verbose) {
PrintAndLog(" r: %s", sprint_hex(rval, 32));
PrintAndLog(" s: %s", sprint_hex(sval, 32));
}
uint8_t xbuf[4096] = {0};
size_t xbuflen = 0;
res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen,
"\x00", 1,
&data[32], 32, // application parameter
&data[0], 32, // challenge parameter
&buf[67], keyHandleLen, // keyHandle
&buf[1], 65, // user public key
NULL, 0);
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[hashp], len - hashp, true);
if (res) {
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
PrintAndLog("Signature is NOT VALID.");
} else {
PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
}
} else {
PrintAndLog("Signature is OK.");
}
} else {
PrintAndLog("Invalid signature. res=%d.", res);
}
PrintAndLog("\nauth command: ");
printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen));
if(chlen || applen)
printf(" %s", paramsPlain?(char *)cdata:sprint_hex_inrow(cdata, 32));
if(applen)
printf(" %s", paramsPlain?(char *)adata:sprint_hex_inrow(adata, 32));
printf("\n");
if (root) {
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65);
JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) {
PrintAndLog("ERROR: can't save the file: %s", fname);
return 200;
}
PrintAndLog("File `%s` saved.", fname);
// free json object
json_decref(root);
}
return 0;
};
int CmdHFFidoAuthenticate(const char *cmd) {
uint8_t data[512] = {0};
uint8_t hdata[250] = {0};
bool public_key_loaded = false;
uint8_t public_key[65] = {0};
int hdatalen = 0;
uint8_t keyHandleLen = 0;
json_t *root = NULL;
CLIParserInit("hf fido auth",
"Initiate a U2F token authentication. Needs key handle and two 32-byte hash number. \nkey handle(var 0..255), challenge parameter (32b) and application parameter (32b).",
"Usage:\n\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n"
"\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f "
"000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters");
void* argtable[] = {
arg_param_begin,
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_lit0("vV", "verbose", "show technical data"),
arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
arg_rem("default mode:", "dont-enforce-user-presence-and-sign"),
arg_lit0("uU", "user", "mode: enforce-user-presence-and-sign"),
arg_lit0("cC", "check", "mode: check-only"),
arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
arg_str0("kK", "key", "public key to verify signature", NULL),
arg_str0(NULL, NULL, "<HEX key handle (var 0..255b)>", NULL),
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool APDULogging = arg_get_lit(1);
bool verbose = arg_get_lit(2);
bool paramsPlain = arg_get_lit(3);
uint8_t controlByte = 0x08;
if (arg_get_lit(5))
controlByte = 0x03;
if (arg_get_lit(6))
controlByte = 0x07;
char fname[250] = {0};
bool err;
root = OpenJson(7, fname, argtable, &err);
if(err)
return 1;
if (root) {
size_t jlen;
JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen);
JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen);
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
keyHandleLen = jlen & 0xff;
data[64] = keyHandleLen;
JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
public_key_loaded = (jlen > 0);
}
// public key
CLIGetHexWithReturn(8, hdata, &hdatalen);
if (hdatalen && hdatalen != 65) {
PrintAndLog("ERROR: public key length must be 65 bytes only.");
return 1;
}
if (hdatalen) {
memmove(public_key, hdata, hdatalen);
public_key_loaded = true;
}
CLIGetHexWithReturn(9, hdata, &hdatalen);
if (hdatalen > 255) {
PrintAndLog("ERROR: application parameter length must be less than 255.");
return 1;
}
if (hdatalen) {
keyHandleLen = hdatalen;
data[64] = keyHandleLen;
memmove(&data[65], hdata, keyHandleLen);
}
if (paramsPlain) {
memset(hdata, 0x00, 32);
CLIGetStrWithReturn(9, hdata, &hdatalen);
if (hdatalen && hdatalen > 16) {
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
return 1;
}
} else {
CLIGetHexWithReturn(10, hdata, &hdatalen);
if (hdatalen && hdatalen != 32) {
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
return 1;
}
}
if (hdatalen)
memmove(data, hdata, 32);
if (paramsPlain) {
memset(hdata, 0x00, 32);
CLIGetStrWithReturn(11, hdata, &hdatalen);
if (hdatalen && hdatalen > 16) {
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
return 1;
}
} else {
CLIGetHexWithReturn(10, hdata, &hdatalen);
if (hdatalen && hdatalen != 32) {
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
return 1;
}
}
if (hdatalen)
memmove(&data[32], hdata, 32);
CLIParserFree();
SetAPDULogging(APDULogging);
// (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only
// challenge parameter [32 bytes]
// application parameter [32 bytes]
// key handle length [1b] = N
// key handle [N]
uint8_t datalen = 32 + 32 + 1 + keyHandleLen;
uint8_t buf[2048] = {0};
size_t len = 0;
uint16_t sw = 0;
DropField();
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
DropField();
return res;
}
if (sw != 0x9000) {
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return 2;
}
res = FIDOAuthentication(data, datalen, controlByte, buf, sizeof(buf), &len, &sw);
DropField();
if (res) {
PrintAndLog("Can't execute authentication command. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 3;
}
PrintAndLog("---------------------------------------------------------------");
PrintAndLog("User presence: %s", (buf[0]?"verified":"not verified"));
uint32_t cntr = (uint32_t)bytes_to_num(&buf[1], 4);
PrintAndLog("Counter: %d", cntr);
PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5));
// check ANSI X9.62 format ECDSA signature (on P-256)
uint8_t rval[300] = {0};
uint8_t sval[300] = {0};
res = ecdsa_asn1_get_signature(&buf[5], len - 5, rval, sval);
if (!res) {
if (verbose) {
PrintAndLog(" r: %s", sprint_hex(rval, 32));
PrintAndLog(" s: %s", sprint_hex(sval, 32));
}
if (public_key_loaded) {
uint8_t xbuf[4096] = {0};
size_t xbuflen = 0;
res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen,
&data[32], 32, // application parameter
&buf[0], 1, // user presence
&buf[1], 4, // counter
data, 32, // challenge parameter
NULL, 0);
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[5], len - 5, true);
if (res) {
if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) {
PrintAndLog("Signature is NOT VALID.");
} else {
PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
}
} else {
PrintAndLog("Signature is OK.");
}
} else {
PrintAndLog("No public key provided. can't check signature.");
}
} else {
PrintAndLog("Invalid signature. res=%d.", res);
}
if (root) {
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
JsonSaveBufAsHexCompact(root, "KeyHandle", &data[65], keyHandleLen);
JsonSaveInt(root, "Counter", cntr);
res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) {
PrintAndLog("ERROR: can't save the file: %s", fname);
return 200;
}
PrintAndLog("File `%s` saved.", fname);
// free json object
json_decref(root);
}
return 0;
};
void CheckSlash(char *fileName) {
if ((fileName[strlen(fileName) - 1] != '/') &&
(fileName[strlen(fileName) - 1] != '\\'))
strcat(fileName, "/");
}
int GetExistsFileNameJson(char *prefixDir, char *reqestedFileName, char *fileName) {
fileName[0] = 0x00;
strcpy(fileName, get_my_executable_directory());
CheckSlash(fileName);
strcat(fileName, prefixDir);
CheckSlash(fileName);
strcat(fileName, reqestedFileName);
if (!strstr(fileName, ".json"))
strcat(fileName, ".json");
if (access(fileName, F_OK) < 0) {
strcpy(fileName, get_my_executable_directory());
CheckSlash(fileName);
strcat(fileName, reqestedFileName);
if (!strstr(fileName, ".json"))
strcat(fileName, ".json");
if (access(fileName, F_OK) < 0) {
return 1; // file not found
}
}
return 0;
}
int CmdHFFido2MakeCredential(const char *cmd) {
json_error_t error;
json_t *root = NULL;
char fname[300] = {0};
CLIParserInit("hf fido make",
"Execute a FIDO2 Make Credentional command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.",
"Usage:\n\thf fido make -> execute command default parameters file `fido2.json`\n"
"\thf fido make test.json -> execute command with parameters file `text.json`");
void* argtable[] = {
arg_param_begin,
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"),
arg_lit0("cC", "cbor", "show CBOR decoded data"),
arg_str0(NULL, NULL, "<json file name>", "JSON input / output file name for parameters. Default `fido2.json`"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool APDULogging = arg_get_lit(1);
bool verbose = arg_get_lit(2);
bool verbose2 = arg_get_lit(2) > 1;
bool showDERTLV = arg_get_lit(3);
bool showCBOR = arg_get_lit(4);
uint8_t jsonname[250] ={0};
char *cjsonname = (char *)jsonname;
int jsonnamelen = 0;
CLIGetStrWithReturn(5, jsonname, &jsonnamelen);
if (!jsonnamelen) {
strcat(cjsonname, "fido2");
jsonnamelen = strlen(cjsonname);
}
CLIParserFree();
SetAPDULogging(APDULogging);
int res = GetExistsFileNameJson("fido", cjsonname, fname);
if(res) {
PrintAndLog("ERROR: Can't found the json file.");
return res;
}
PrintAndLog("fname: %s\n", fname);
root = json_load_file(fname, 0, &error);
if (!root) {
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
return 1;
}
uint8_t data[2048] = {0};
size_t datalen = 0;
uint8_t buf[2048] = {0};
size_t len = 0;
uint16_t sw = 0;
DropField();
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
DropField();
return res;
}
if (sw != 0x9000) {
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return 2;
}
res = FIDO2CreateMakeCredentionalReq(root, data, sizeof(data), &datalen);
if (res)
return res;
if (showCBOR) {
PrintAndLog("CBOR make credentional request:");
PrintAndLog("---------------- CBOR ------------------");
TinyCborPrintFIDOPackage(fido2CmdMakeCredential, false, data, datalen);
PrintAndLog("---------------- CBOR ------------------");
}
res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw);
DropField();
if (res) {
PrintAndLog("Can't execute make credential command. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 3;
}
if(buf[0]) {
PrintAndLog("FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
return 0;
}
PrintAndLog("MakeCredential result (%d b) OK.", len);
if (showCBOR) {
PrintAndLog("CBOR make credentional response:");
PrintAndLog("---------------- CBOR ------------------");
TinyCborPrintFIDOPackage(fido2CmdMakeCredential, true, &buf[1], len - 1);
PrintAndLog("---------------- CBOR ------------------");
}
// parse returned cbor
FIDO2MakeCredentionalParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR, showDERTLV);
if (root) {
res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) {
PrintAndLog("ERROR: can't save the file: %s", fname);
return 200;
}
PrintAndLog("File `%s` saved.", fname);
}
json_decref(root);
return 0;
};
int CmdHFFido2GetAssertion(const char *cmd) {
json_error_t error;
json_t *root = NULL;
char fname[300] = {0};
CLIParserInit("hf fido assert",
"Execute a FIDO2 Get Assertion command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.",
"Usage:\n\thf fido assert -> execute command default parameters file `fido2.json`\n"
"\thf fido assert test.json -l -> execute command with parameters file `text.json` and add to request CredentialId");
void* argtable[] = {
arg_param_begin,
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
arg_lit0("cC", "cbor", "show CBOR decoded data"),
arg_lit0("lL", "list", "add CredentialId from json to allowList. Needs if `rk` option is `false` (authenticator don't store credential to its memory)"),
arg_str0(NULL, NULL, "<json file name>", "JSON input / output file name for parameters. Default `fido2.json`"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool APDULogging = arg_get_lit(1);
bool verbose = arg_get_lit(2);
bool verbose2 = arg_get_lit(2) > 1;
bool showCBOR = arg_get_lit(3);
bool createAllowList = arg_get_lit(4);
uint8_t jsonname[250] ={0};
char *cjsonname = (char *)jsonname;
int jsonnamelen = 0;
CLIGetStrWithReturn(5, jsonname, &jsonnamelen);
if (!jsonnamelen) {
strcat(cjsonname, "fido2");
jsonnamelen = strlen(cjsonname);
}
CLIParserFree();
SetAPDULogging(APDULogging);
int res = GetExistsFileNameJson("fido", "fido2", fname);
if(res) {
PrintAndLog("ERROR: Can't found the json file.");
return res;
}
PrintAndLog("fname: %s\n", fname);
root = json_load_file(fname, 0, &error);
if (!root) {
PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text);
return 1;
}
uint8_t data[2048] = {0};
size_t datalen = 0;
uint8_t buf[2048] = {0};
size_t len = 0;
uint16_t sw = 0;
DropField();
res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
DropField();
return res;
}
if (sw != 0x9000) {
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return 2;
}
res = FIDO2CreateGetAssertionReq(root, data, sizeof(data), &datalen, createAllowList);
if (res)
return res;
if (showCBOR) {
PrintAndLog("CBOR get assertion request:");
PrintAndLog("---------------- CBOR ------------------");
TinyCborPrintFIDOPackage(fido2CmdGetAssertion, false, data, datalen);
PrintAndLog("---------------- CBOR ------------------");
}
res = FIDO2GetAssertion(data, datalen, buf, sizeof(buf), &len, &sw);
DropField();
if (res) {
PrintAndLog("Can't execute get assertion command. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 3;
}
if(buf[0]) {
PrintAndLog("FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0]));
return 0;
}
PrintAndLog("GetAssertion result (%d b) OK.", len);
if (showCBOR) {
PrintAndLog("CBOR get assertion response:");
PrintAndLog("---------------- CBOR ------------------");
TinyCborPrintFIDOPackage(fido2CmdGetAssertion, true, &buf[1], len - 1);
PrintAndLog("---------------- CBOR ------------------");
}
// parse returned cbor
FIDO2GetAssertionParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR);
if (root) {
res = json_dump_file(root, fname, JSON_INDENT(2));
if (res) {
PrintAndLog("ERROR: can't save the file: %s", fname);
return 200;
}
PrintAndLog("File `%s` saved.", fname);
}
json_decref(root);
return 0;
};
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help."},
{"info", CmdHFFidoInfo, 0, "Info about FIDO tag."},
{"reg", CmdHFFidoRegister, 0, "FIDO U2F Registration Message."},
{"auth", CmdHFFidoAuthenticate, 0, "FIDO U2F Authentication Message."},
{"make", CmdHFFido2MakeCredential, 0, "FIDO2 MakeCredential command."},
{"assert", CmdHFFido2GetAssertion, 0, "FIDO2 GetAssertion command."},
{NULL, NULL, 0, NULL}
};
int CmdHFFido(const char *Cmd) {
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable);
return 0;
}

27
client/cmdhffido.h Normal file
View file

@ -0,0 +1,27 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency FIDO U2F and FIDO2 contactless authenticators
//-----------------------------------------------------------------------------
//
// Documentation here:
//
// FIDO Alliance specifications
// https://fidoalliance.org/download/
// FIDO NFC Protocol Specification v1.0
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html
// FIDO U2F Raw Message Formats
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html
//-----------------------------------------------------------------------------
#ifndef CMDHFFIDO_H__
#define CMDHFFIDO_H__
extern int CmdHFFido(const char *Cmd);
#endif

File diff suppressed because it is too large Load diff

View file

@ -13,28 +13,6 @@
#define CMDHFICLASS_H__
int CmdHFiClass(const char *Cmd);
int HFiClassReader(bool loop, bool verbose);
int CmdHFiClassCalcNewKey(const char *Cmd);
int CmdHFiClassCloneTag(const char *Cmd);
int CmdHFiClassDecrypt(const char *Cmd);
int CmdHFiClassEncryptBlk(const char *Cmd);
int CmdHFiClassELoad(const char *Cmd);
int CmdHFiClassList(const char *Cmd);
int HFiClassReader(const char *Cmd, bool loop, bool verbose);
int CmdHFiClassReader(const char *Cmd);
int CmdHFiClassReader_Dump(const char *Cmd);
int CmdHFiClassReader_Replay(const char *Cmd);
int CmdHFiClassReadKeyFile(const char *filename);
int CmdHFiClassReadTagFile(const char *Cmd);
int CmdHFiClass_ReadBlock(const char *Cmd);
int CmdHFiClass_TestMac(const char *Cmd);
int CmdHFiClassManageKeys(const char *Cmd);
int CmdHFiClass_loclass(const char *Cmd);
int CmdHFiClassSnoop(const char *Cmd);
int CmdHFiClassSim(const char *Cmd);
int CmdHFiClassWriteKeyFile(const char *Cmd);
int CmdHFiClass_WriteBlock(const char *Cmd);
int CmdHFiClassCheckKeys(const char *Cmd);
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize);
void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite);
#endif

View file

@ -18,6 +18,7 @@
#include "cmdparser.h"
#include "cmdmain.h"
#include "util.h"
#include "../include/legic.h"
static int CmdHelp(const char *Cmd);
@ -214,7 +215,23 @@ int CmdLegicRFRead(const char *Cmd)
if(byte_count + offset > 1024) byte_count = 1024 - offset;
UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}};
SendCommand(&c);
return 0;
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
switch (resp.arg[0]) {
legic_card_select_t card;
case 0:
memcpy(&card, resp.d.asBytes, sizeof(card));
PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize);
PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7);
break;
case 1:
PrintAndLog("No or unknown card found, aborting");
break;
case 2:
PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]);
break;
}
return resp.arg[0];
}
int CmdLegicLoad(const char *Cmd)

View file

@ -1,11 +1,12 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// Copyright (C) Merlok - 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Command: hf mf list. It shows data from arm buffer.
// Command: hf list. It shows data from arm buffer.
//-----------------------------------------------------------------------------
#include "cmdhflist.h"
@ -17,13 +18,32 @@
#include <stdbool.h>
#include "util.h"
#include "ui.h"
#include "cliparser/cliparser.h"
#include "comms.h"
#include "iso14443crc.h"
#include "iso15693tools.h"
#include "parity.h"
#include "protocols.h"
#include "crapto1/crapto1.h"
#include "mifarehost.h"
#include "mifaredefault.h"
#include "mifare/mifarehost.h"
#include "mifare/mifaredefault.h"
#include "usb_cmd.h"
#include "pcsc.h"
typedef struct {
uint32_t uid; // UID
uint32_t nt; // tag challenge
uint32_t nt_enc; // encrypted tag challenge
uint8_t nt_enc_par; // encrypted tag challenge parity
uint32_t nr_enc; // encrypted reader challenge
uint32_t ar_enc; // encrypted reader response
uint8_t ar_enc_par; // encrypted reader response parity
uint32_t at_enc; // encrypted tag response
uint8_t at_enc_par; // encrypted tag response parity
bool first_auth; // is first authentication
uint32_t ks2; // ar ^ ar_enc
uint32_t ks3; // at ^ at_enc
} TAuthData;
enum MifareAuthSeq {
masNone,
@ -35,10 +55,11 @@ enum MifareAuthSeq {
masData,
masError,
};
static enum MifareAuthSeq MifareAuthState;
static TAuthData AuthData;
void ClearAuthData() {
static void ClearAuthData() {
AuthData.uid = 0;
AuthData.nt = 0;
AuthData.first_auth = true;
@ -55,7 +76,7 @@ void ClearAuthData() {
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
static uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
@ -71,7 +92,23 @@ uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
}
}
uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
static uint8_t iso14443_4_CRC_check(uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
if(len <= 2) return 2;
ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2);
if (b1 != data[len-2] || b2 != data[len-1]) {
return 0;
} else {
return 1;
}
}
static uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
switch(MifareAuthState) {
case masNone:
@ -82,8 +119,102 @@ uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
}
}
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
/**
* @brief iso14443B_CRC_check Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
static uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
if(len <= 2) return 2;
ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2);
if(b1 != data[len-2] || b2 != data[len-1]) {
return 0;
} else {
return 1;
}
}
static uint8_t iso15693_CRC_check(uint8_t* d, uint16_t n)
{
if (n <= 2) return 2;
return (Iso15693Crc(d, n) == ISO15693_CRC_CHECK ? 1 : 0);
}
/**
* @brief iclass_CRC_Ok Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes
uint8_t b1, b2;
if(!isResponse)//Commands to tag
{
/**
These commands should have CRC. Total length leftmost
4 READ
4 READ4
12 UPDATE - unsecured, ends with CRC16
14 UPDATE - secured, ends with signature instead
4 PAGESEL
**/
if(len == 4 || len == 12)//Covers three of them
{
//Don't include the command byte
ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2);
return b1 == data[len -2] && b2 == data[len-1];
}
return 2;
}else{
/**
These tag responses should have CRC. Total length leftmost
10 READ data[8] crc[2]
34 READ4 data[32]crc[2]
10 UPDATE data[8] crc[2]
10 SELECT csn[8] crc[2]
10 IDENTIFY asnb[8] crc[2]
10 PAGESEL block1[8] crc[2]
10 DETECT csn[8] crc[2]
These should not
4 CHECK chip_response[4]
8 READCHECK data[8]
1 ACTALL sof[1]
1 ACT sof[1]
In conclusion, without looking at the command; any response
of length 10 or 34 should have CRC
**/
if(len != 10 && len != 34) return true;
ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2);
return b1 == data[len -2] && b2 == data[len-1];
}
}
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
switch(cmd[0])
{
case ICLASS_CMD_ACTALL: snprintf(exp, size, "ACTALL"); break;
@ -99,7 +230,8 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
case ICLASS_CMD_PAGESEL: snprintf(exp,size, "PAGESEL(%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KC: snprintf(exp,size, "READCHECK[Kc](%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KD: snprintf(exp,size, "READCHECK[Kd](%d)", cmd[1]); break;
case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break;
case ICLASS_CMD_CHECK_KC:
case ICLASS_CMD_CHECK_KD: snprintf(exp,size, "CHECK"); break;
case ICLASS_CMD_DETECT: snprintf(exp,size, "DETECT"); break;
case ICLASS_CMD_HALT: snprintf(exp,size, "HALT"); break;
case ICLASS_CMD_UPDATE: snprintf(exp,size, "UPDATE(%d)",cmd[1]); break;
@ -110,35 +242,34 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
return;
}
void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
if(cmd[0] == 0x26)
{
void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
if (cmdsize >= 2) {
switch (cmd[1]) {
case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break;
case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break;
default: snprintf(exp,size,"?"); break;
// Mandatory Commands, all Tags must support them:
case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");return;
case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");return;
// Optional Commands, Tags may support them:
case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");return;
case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");return;
case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");return;
case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");return;
case ISO15693_WRITE_MULTI_BLOCK :snprintf(exp, size, "WRITE_MULTI_BLOCK");return;
case ISO15693_SELECT :snprintf(exp, size, "SELECT");return;
case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");return;
case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");return;
case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");return;
case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");return;
case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");return;
case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");return;
case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");return;
default: break;
}
}
}else if(cmd[0] == 0x02)
{
switch(cmd[1])
{
case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break;
case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break;
case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break;
case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break;
case ISO15693_SELECT :snprintf(exp, size, "SELECT");break;
case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break;
case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break;
case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break;
case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break;
case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break;
case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break;
case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break;
default: snprintf(exp,size,"?"); break;
}
if (cmd[1] > ISO15693_STAYQUIET && cmd[1] < ISO15693_READBLOCK) snprintf(exp, size, "Mandatory RFU");
else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU");
else if ( cmd[1] >= 0xA0 && cmd[1] <= 0xDF ) snprintf(exp, size, "Custom command");
else if ( cmd[1] >= 0xE0 && cmd[1] <= 0xFF ) snprintf(exp, size, "Proprietary command");
}
}
@ -162,6 +293,69 @@ void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
}
void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch ( cmd[1] ){
case ISO7816_READ_BINARY :snprintf(exp, size, "READ BINARY");break;
case ISO7816_WRITE_BINARY :snprintf(exp, size, "WRITE BINARY");break;
case ISO7816_UPDATE_BINARY :snprintf(exp, size, "UPDATE BINARY");break;
case ISO7816_ERASE_BINARY :snprintf(exp, size, "ERASE BINARY");break;
case ISO7816_READ_RECORDS :snprintf(exp, size, "READ RECORD(S)");break;
case ISO7816_WRITE_RECORD :snprintf(exp, size, "WRITE RECORD");break;
case ISO7816_APPEND_RECORD :snprintf(exp, size, "APPEND RECORD");break;
case ISO7816_UPDATE_DATA :snprintf(exp, size, "UPDATE DATA");break;
case ISO7816_GET_DATA :snprintf(exp, size, "GET DATA");break;
case ISO7816_PUT_DATA :snprintf(exp, size, "PUT DATA");break;
case ISO7816_SELECT_FILE :snprintf(exp, size, "SELECT FILE");break;
case ISO7816_VERIFY :snprintf(exp, size, "VERIFY");break;
case ISO7816_INTERNAL_AUTHENTICATE :snprintf(exp, size, "INTERNAL AUTHENTICATE");break;
case ISO7816_EXTERNAL_AUTHENTICATE :snprintf(exp, size, "EXTERNAL AUTHENTICATE");break;
case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break;
case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break;
case ISO7816_GET_RESPONSE :snprintf(exp, size, "GET RESPONSE");break;
case ISO7816_ENVELOPE :snprintf(exp, size, "ENVELOPE");break;
case ISO7816_GET_PROCESSING_OPTIONS :snprintf(exp, size, "GET PROCESSING OPTIONS");break;
default :snprintf(exp,size,"?"); break;
}
}
void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
// S-block
if ((cmd[0] & 0xc3) == 0xc2) {
switch (cmd[0] & 0x30) {
case 0x00 : snprintf(exp, size, "S-block DESELECT"); break;
case 0x30 : snprintf(exp, size, "S-block WTX"); break;
default : snprintf(exp, size, "S-block (RFU)"); break;
}
}
// R-block (ack)
else if ((cmd[0] & 0xe0) == 0xa0) {
if ((cmd[0] & 0x10) == 0)
snprintf(exp, size, "R-block ACK");
else
snprintf(exp, size, "R-block NACK");
}
// I-block
else {
int pos = 1;
switch (cmd[0] & 0x0c) {
case 0x08: // CID following
case 0x04: // NAD following
pos = 2;
break;
case 0x0c: // CID and NAD following
pos = 3;
break;
default:
pos = 1; // no CID, no NAD
break;
}
annotateIso7816(exp, size, &cmd[pos], cmdsize-pos);
}
}
/**
06 00 = INITIATE
0E xx = SELECT ID (xx = Chip-ID)
@ -173,8 +367,7 @@ void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
**/
void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
switch(cmd[0]){
case ISO14443B_REQB : snprintf(exp,size,"REQB");break;
case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break;
@ -192,8 +385,7 @@ void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
}
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) {
switch(cmd[0])
{
case ISO14443A_CMD_WUPA:
@ -224,8 +416,8 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
case ISO14443A_CMD_REQA:
snprintf(exp,size,"REQA");
break;
case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
case MIFARE_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
case MIFARE_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_HALT:
snprintf(exp,size,"HALT");
MifareAuthState = masNone;
@ -367,7 +559,103 @@ void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8
}
bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) {
static uint64_t GetCrypto1ProbableKey(TAuthData *ad) {
struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, ad->nr_enc, 1);
lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0);
uint64_t lfsr = 0;
crypto1_get_lfsr(revstate, &lfsr);
crypto1_destroy(revstate);
return lfsr;
}
static bool NTParityChk(TAuthData *ad, uint32_t ntx) {
if (
(oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) ||
(oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) ||
(oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01))
)
return false;
uint32_t ar = prng_successor(ntx, 64);
if (
(oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) ||
(oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) ||
(oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01))
)
return false;
uint32_t at = prng_successor(ntx, 96);
if (
(oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) ||
(oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) ||
(oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) ||
(oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01))
)
return false;
return true;
}
static bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) {
for (int i = 0; i < cmdsize - 1; i++) {
if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01))
return false;
}
return true;
}
static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) {
uint8_t buf[32] = {0};
struct Crypto1State *pcs;
AuthData.ks2 = 0;
AuthData.ks3 = 0;
pcs = crypto1_create(key);
uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc;
uint32_t ar = prng_successor(nt1, 64);
uint32_t at = prng_successor(nt1, 96);
crypto1_word(pcs, ad->nr_enc, 1);
// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr
uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc;
uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc;
if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) {
crypto1_destroy(pcs);
return false;
}
memcpy(buf, cmd, cmdsize);
mf_crypto1_decrypt(pcs, buf, cmdsize, 0);
crypto1_destroy(pcs);
if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity))
return false;
if(!CheckCrc14443(CRC_14443_A, buf, cmdsize))
return false;
AuthData.nt = nt1;
AuthData.ks2 = AuthData.ar_enc ^ ar;
AuthData.ks3 = AuthData.at_enc ^ at;
return true;
}
static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) {
static struct Crypto1State *traceCrypto1;
static uint64_t mfLastKey;
@ -514,93 +802,448 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
return *mfDataLen > 0;
}
bool NTParityChk(TAuthData *ad, uint32_t ntx) {
if (
(oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) ||
(oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) ||
(oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01))
)
return false;
uint32_t ar = prng_successor(ntx, 64);
if (
(oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) ||
(oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) ||
(oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01))
)
return false;
bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) {
return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen);
}
uint32_t at = prng_successor(ntx, 96);
if (
(oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) ||
(oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) ||
(oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) ||
(oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01))
)
return false;
bool next_record_is_response(uint16_t tracepos, uint8_t *trace) {
uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t)));
return(next_records_datalen & 0x8000);
}
bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) {
#define MAX_TOPAZ_READER_CMD_LEN 16
uint32_t last_timestamp = timestamp + *duration;
if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false;
memcpy(topaz_reader_command, frame, *data_len);
while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) {
uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos));
*tracepos += sizeof(uint32_t);
uint16_t next_duration = *((uint16_t *)(trace + *tracepos));
*tracepos += sizeof(uint16_t);
uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF;
*tracepos += sizeof(uint16_t);
uint8_t *next_frame = (trace + *tracepos);
*tracepos += next_data_len;
if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) {
memcpy(topaz_reader_command + *data_len, next_frame, next_data_len);
*data_len += next_data_len;
last_timestamp = next_timestamp + next_duration;
} else {
// rewind and exit
*tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t);
break;
}
uint16_t next_parity_len = (next_data_len-1)/8 + 1;
*tracepos += next_parity_len;
}
*duration = last_timestamp - timestamp;
return true;
}
bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) {
uint8_t buf[32] = {0};
struct Crypto1State *pcs;
AuthData.ks2 = 0;
AuthData.ks3 = 0;
uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes, uint32_t *prev_EOT, bool times_in_us) {
bool isResponse;
uint16_t data_len, parity_len;
uint32_t duration;
uint8_t topaz_reader_command[9];
uint32_t timestamp, first_timestamp;
uint32_t EndOfTransmissionTimestamp = 0;
char explanation[30] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
pcs = crypto1_create(key);
uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc;
uint32_t ar = prng_successor(nt1, 64);
uint32_t at = prng_successor(nt1, 96);
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
crypto1_word(pcs, ad->nr_enc, 1);
// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr
uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc;
uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc;
first_timestamp = *((uint32_t *)(trace));
timestamp = *((uint32_t *)(trace + tracepos));
if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) {
crypto1_destroy(pcs);
return false;
tracepos += 4;
duration = *((uint16_t *)(trace + tracepos));
tracepos += 2;
data_len = *((uint16_t *)(trace + tracepos));
tracepos += 2;
if (data_len & 0x8000) {
data_len &= 0x7fff;
isResponse = true;
} else {
isResponse = false;
}
parity_len = (data_len-1)/8 + 1;
if (tracepos + data_len + parity_len > traceLen) {
return traceLen;
}
uint8_t *frame = trace + tracepos;
tracepos += data_len;
uint8_t *parityBytes = trace + tracepos;
tracepos += parity_len;
if (protocol == TOPAZ && !isResponse) {
// topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each.
// merge them:
if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) {
frame = topaz_reader_command;
}
}
memcpy(buf, cmd, cmdsize);
mf_crypto1_decrypt(pcs, buf, cmdsize, 0);
crypto1_destroy(pcs);
if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity))
return false;
if(!CheckCrc14443(CRC_14443_A, buf, cmdsize))
return false;
AuthData.nt = nt1;
AuthData.ks2 = AuthData.ar_enc ^ ar;
AuthData.ks3 = AuthData.at_enc ^ at;
return true;
// adjust for different time scales
if (protocol == ICLASS || protocol == ISO_15693) {
duration *= 32;
}
bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) {
for (int i = 0; i < cmdsize - 1; i++) {
if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01))
return false;
//Check the CRC status
uint8_t crcStatus = 2;
if (data_len > 2) {
switch (protocol) {
case ICLASS:
crcStatus = iclass_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443B:
case TOPAZ:
crcStatus = iso14443B_CRC_check(isResponse, frame, data_len);
break;
case PROTO_MIFARE:
crcStatus = mifare_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443A:
crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443_4:
crcStatus = iso14443_4_CRC_check(frame, data_len);
break;
case ISO_15693:
crcStatus = iso15693_CRC_check(frame, data_len);
break;
default:
break;
}
}
//0 CRC-command, CRC not ok
//1 CRC-command, CRC ok
//2 Not crc-command
//--- Draw the data column
char line[16][110];
for (int j = 0; j < data_len && j/16 < 16; j++) {
uint8_t parityBits = parityBytes[j>>3];
if (protocol != ISO_14443B
&& protocol != ISO_15693
&& protocol != ICLASS
&& protocol != ISO_7816_4
&& (isResponse || protocol == ISO_14443A)
&& (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) {
snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]);
} else {
snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]);
}
}
return true;
if (markCRCBytes) {
if (crcStatus == 0 || crcStatus == 1) { //CRC-command
char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4);
(*pos1) = '[';
char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4);
sprintf(pos2, "%c", ']');
}
}
uint64_t GetCrypto1ProbableKey(TAuthData *ad) {
struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, ad->nr_enc, 1);
lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0);
uint64_t lfsr = 0;
crypto1_get_lfsr(revstate, &lfsr);
crypto1_destroy(revstate);
return lfsr;
// mark short bytes (less than 8 Bit + Parity)
if (protocol == ISO_14443A || protocol == PROTO_MIFARE) {
if (duration < 128 * (9 * data_len)) {
line[(data_len-1)/16][((data_len-1)%16) * 4 + 3] = '\'';
}
}
if (data_len == 0) {
if (protocol == ICLASS && duration == 2048) {
sprintf(line[0], " <SOF>");
} else if (protocol == ISO_15693 && duration == 512) {
sprintf(line[0], " <EOF>");
} else {
sprintf(line[0], " <empty trace - possible error>");
}
}
//--- Draw the CRC column
char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " "));
if (protocol == PROTO_MIFARE)
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
if (!isResponse) {
switch(protocol) {
case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break;
case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break;
case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break;
case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break;
case ISO_15693: annotateIso15693(explanation,sizeof(explanation),frame,data_len); break;
case ISO_7816_4: annotateIso7816(explanation, sizeof(explanation), frame, data_len); break;
case ISO_14443_4: annotateIso14443_4(explanation, sizeof(explanation), frame, data_len); break;
default: break;
}
}
uint32_t previousEndOfTransmissionTimestamp = 0;
if (prev_EOT) {
if (*prev_EOT) {
previousEndOfTransmissionTimestamp = *prev_EOT;
} else {
previousEndOfTransmissionTimestamp = timestamp;
}
}
EndOfTransmissionTimestamp = timestamp + duration;
if (prev_EOT) *prev_EOT = EndOfTransmissionTimestamp;
int num_lines = MIN((data_len - 1)/16 + 1, 16);
for (int j = 0; j < num_lines ; j++) {
if (j == 0) {
uint32_t time1 = timestamp - first_timestamp;
uint32_t time2 = EndOfTransmissionTimestamp - first_timestamp;
if (prev_EOT) {
time1 = timestamp - previousEndOfTransmissionTimestamp;
time2 = duration;
}
if (times_in_us) {
PrintAndLog(" %10.1f | %10.1f | %s |%-64s | %s| %s",
(float)time1/13.56,
(float)time2/13.56,
isResponse ? "Tag" : "Rdr",
line[j],
(j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : "");
} else {
PrintAndLog(" %10" PRIu32 " | %10" PRIu32 " | %s |%-64s | %s| %s",
time1,
time2,
isResponse ? "Tag" : "Rdr",
line[j],
(j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : "");
}
} else {
PrintAndLog(" | | |%-64s | %s| %s",
line[j],
(j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : "");
}
}
if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) {
memset(explanation, 0x00, sizeof(explanation));
if (!isResponse) {
explanation[0] = '>';
annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen);
}
uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen);
PrintAndLog(" | * | dec |%-64s | %-4s| %s",
sprint_hex(mfData, mfDataLen),
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
(true) ? explanation : "");
};
if (is_last_record(tracepos, trace, traceLen)) return traceLen;
if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) {
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d",
(EndOfTransmissionTimestamp - first_timestamp),
(next_timestamp - first_timestamp),
" ",
(next_timestamp - EndOfTransmissionTimestamp));
}
return tracepos;
}
int CmdHFList(const char *Cmd) {
CLIParserInit("hf list", "\nList or save protocol data.",
"examples: hf list 14a -f -- interpret as ISO14443A communication and display Frame Delay Times\n"\
" hf list iclass -- interpret as iClass trace\n"\
" hf list -s myCardTrace.trc -- save trace for later use\n"\
" hf list 14a -l myCardTrace.trc -- load trace and interpret as ISO14443A communication\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("f", "fdt", "display fdt (frame delay times)"),
arg_lit0("r", "relative", "show relative times (gap and duration)"),
arg_lit0("c", "crc" , "mark CRC bytes"),
arg_lit0("p", "pcsc", "show trace buffer from PCSC card reader instead of PM3"),
arg_str0("l", "load", "<filename>", "load trace from file"),
arg_str0("s", "save", "<filename>", "save trace to file"),
arg_lit0("u", "us", "display times in microseconds instead of clock cycles"),
arg_str0(NULL, NULL, "<protocol>", "protocol to interpret. Possible values:\n"\
"\traw - just show raw data without annotations (default)\n"\
"\t14a - interpret data as ISO14443A communications\n"\
"\tmf - interpret data as ISO14443A communications and decrypt Mifare Crypto1 stream\n"\
"\t14b - interpret data as ISO14443B communications\n"\
"\t15 - interpret data as ISO15693 communications\n"\
"\ticlass - interpret data as iClass communications\n"\
"\ttopaz - interpret data as Topaz communications\n"\
"\t7816 - interpret data as 7816-4 APDU communications\n"\
"\t14-4 - interpret data as ISO14443-4 communications"),
arg_param_end
};
if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){
CLIParserFree();
return 0;
}
bool showWaitCycles = arg_get_lit(1);
bool relative_times = arg_get_lit(2);
bool markCRCBytes = arg_get_lit(3);
bool PCSCtrace = arg_get_lit(4);
bool loadFromFile = arg_get_str_len(5);
bool saveToFile = arg_get_str_len(6);
bool times_in_us = arg_get_lit(7);
uint32_t previous_EOT = 0;
uint32_t *prev_EOT = NULL;
if (relative_times) {
prev_EOT = &previous_EOT;
}
char load_filename[FILE_PATH_SIZE+1] = {0};
if (loadFromFile) {
strncpy(load_filename, arg_get_str(5)->sval[0], FILE_PATH_SIZE);
}
char save_filename[FILE_PATH_SIZE+1] = {0};
if (saveToFile) {
strncpy(save_filename, arg_get_str(6)->sval[0], FILE_PATH_SIZE);
}
uint8_t protocol = -1;
if (arg_get_str_len(8)) {
if (strcmp(arg_get_str(8)->sval[0], "iclass") == 0) protocol = ICLASS;
else if(strcmp(arg_get_str(8)->sval[0], "14a") == 0) protocol = ISO_14443A;
else if(strcmp(arg_get_str(8)->sval[0], "mf") == 0) protocol = PROTO_MIFARE;
else if(strcmp(arg_get_str(8)->sval[0], "14b") == 0) protocol = ISO_14443B;
else if(strcmp(arg_get_str(8)->sval[0], "topaz") == 0) protocol = TOPAZ;
else if(strcmp(arg_get_str(8)->sval[0], "7816") == 0) protocol = ISO_7816_4;
else if(strcmp(arg_get_str(8)->sval[0], "14-4") == 0) protocol = ISO_14443_4;
else if(strcmp(arg_get_str(8)->sval[0], "15") == 0) protocol = ISO_15693;
else if(strcmp(arg_get_str(8)->sval[0], "raw") == 0) protocol = -1;//No crc, no annotations
else {
PrintAndLog("hf list: invalid argument \"%s\"\nTry 'hf list --help' for more information.", arg_get_str(8)->sval[0]);
CLIParserFree();
return 0;
}
}
CLIParserFree();
uint8_t *trace;
uint32_t tracepos = 0;
uint32_t traceLen = 0;
if (loadFromFile) {
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
FILE *tracefile = NULL;
size_t bytes_read;
trace = malloc(TRACE_CHUNK_SIZE);
if (trace == NULL) {
PrintAndLog("Cannot allocate memory for trace");
return 2;
}
if ((tracefile = fopen(load_filename,"rb")) == NULL) {
PrintAndLog("Could not open file %s", load_filename);
free(trace);
return 0;
}
while (!feof(tracefile)) {
bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile);
traceLen += bytes_read;
if (!feof(tracefile)) {
uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
fclose(tracefile);
return 2;
}
trace = p;
}
}
fclose(tracefile);
} else if (PCSCtrace) {
trace = pcsc_get_trace_addr();
traceLen = pcsc_get_traceLen();
} else {
trace = malloc(USB_CMD_DATA_SIZE);
// Query for the size of the trace
UsbCommand response;
if (!(GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, 500, false))) {
return 1;
}
traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(trace, traceLen);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
return 2;
}
trace = p;
if (!(GetFromBigBuf(trace, traceLen, 0, NULL, 500, false))) {
return 1;
}
}
}
if (saveToFile) {
FILE *tracefile = NULL;
if ((tracefile = fopen(save_filename,"wb")) == NULL) {
PrintAndLog("Could not create file %s", save_filename);
return 1;
}
fwrite(trace, 1, traceLen, tracefile);
PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, save_filename);
fclose(tracefile);
} else {
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLog("");
if (relative_times) {
PrintAndLog("Gap = time between transfers. Duration = duration of data transfer. Src = Source of transfer");
} else {
PrintAndLog("Start = Start of Frame, End = End of Frame. Src = Source of transfer");
}
if (times_in_us) {
PrintAndLog("All times are in microseconds");
} else {
PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
}
PrintAndLog("");
if (relative_times) {
PrintAndLog(" Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |");
} else {
PrintAndLog(" Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |");
}
PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|");
ClearAuthData();
while(tracepos < traceLen) {
tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes, prev_EOT, times_in_us);
}
}
free(trace);
return 0;
}

View file

@ -1,4 +1,5 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// Copyright (C) Merlok - 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
@ -10,38 +11,6 @@
#ifndef CMDHFLIST_H
#define CMDHFLIST_H
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
extern int CmdHFList(const char *Cmd);
typedef struct {
uint32_t uid; // UID
uint32_t nt; // tag challenge
uint32_t nt_enc; // encrypted tag challenge
uint8_t nt_enc_par; // encrypted tag challenge parity
uint32_t nr_enc; // encrypted reader challenge
uint32_t ar_enc; // encrypted reader response
uint8_t ar_enc_par; // encrypted reader response parity
uint32_t at_enc; // encrypted tag response
uint8_t at_enc_par; // encrypted tag response parity
bool first_auth; // is first authentication
uint32_t ks2; // ar ^ ar_enc
uint32_t ks3; // at ^ at_enc
} TAuthData;
extern void ClearAuthData();
extern uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len);
extern uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len);
extern void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse);
extern bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen);
extern bool NTParityChk(TAuthData *ad, uint32_t ntx);
extern bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity);
extern bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc);
extern uint64_t GetCrypto1ProbableKey(TAuthData *ad);
#endif // CMDHFLIST
#endif // CMDHFLIST_H

File diff suppressed because it is too large Load diff

View file

@ -11,37 +11,6 @@
#ifndef CMDHFMF_H__
#define CMDHFMF_H__
#include "mifaredefault.h"
extern int CmdHFMF(const char *Cmd);
extern int CmdHF14AMfDbg(const char* cmd);
extern int CmdHF14AMfRdBl(const char* cmd);
extern int CmdHF14AMfURdBl(const char* cmd);
extern int CmdHF14AMfRdSc(const char* cmd);
extern int CmdHF14SMfURdCard(const char* cmd);
extern int CmdHF14AMfDump(const char* cmd);
extern int CmdHF14AMfRestore(const char* cmd);
extern int CmdHF14AMfWrBl(const char* cmd);
extern int CmdHF14AMfUWrBl(const char* cmd);
extern int CmdHF14AMfChk(const char* cmd);
extern int CmdHF14AMifare(const char* cmd);
extern int CmdHF14AMfNested(const char* cmd);
extern int CmdHF14AMfSniff(const char* cmd);
extern int CmdHF14AMf1kSim(const char* cmd);
extern int CmdHF14AMfEClear(const char* cmd);
extern int CmdHF14AMfEGet(const char* cmd);
extern int CmdHF14AMfESet(const char* cmd);
extern int CmdHF14AMfELoad(const char* cmd);
extern int CmdHF14AMfESave(const char* cmd);
extern int CmdHF14AMfECFill(const char* cmd);
extern int CmdHF14AMfEKeyPrn(const char* cmd);
extern int CmdHF14AMfCWipe(const char* cmd);
extern int CmdHF14AMfCSetUID(const char* cmd);
extern int CmdHF14AMfCSetBlk(const char* cmd);
extern int CmdHF14AMfCGetBlk(const char* cmd);
extern int CmdHF14AMfCGetSc(const char* cmd);
extern int CmdHF14AMfCLoad(const char* cmd);
extern int CmdHF14AMfCSave(const char* cmd);
#endif

867
client/cmdhfmfp.c Normal file
View file

@ -0,0 +1,867 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
// Copyright (C) 2018 drHatson
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Plus commands
//-----------------------------------------------------------------------------
#include "cmdhfmfp.h"
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "comms.h"
#include "cmdmain.h"
#include "util.h"
#include "ui.h"
#include "cmdhf14a.h"
#include "mifare.h"
#include "mifare/mifare4.h"
#include "mifare/mad.h"
#include "mifare/ndef.h"
#include "cliparser/cliparser.h"
#include "crypto/libpcrypto.h"
#include "emv/dump.h"
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static int CmdHelp(const char *Cmd);
int CmdHFMFPInfo(const char *cmd) {
if (cmd && strlen(cmd) > 0)
PrintAndLog("WARNING: command don't have any parameters.\n");
// info about 14a part
CmdHF14AInfo("");
// Mifare Plus info
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if (select_status == 1 || select_status == 2) {
PrintAndLog("----------------------------------------------");
PrintAndLog("Mifare Plus info:");
// MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
if (ATQA == 0x0004) PrintAndLog("ATQA: Mifare Plus 2k 4bUID");
if (ATQA == 0x0002) PrintAndLog("ATQA: Mifare Plus 4k 4bUID");
if (ATQA == 0x0044) PrintAndLog("ATQA: Mifare Plus 2k 7bUID");
if (ATQA == 0x0042) PrintAndLog("ATQA: Mifare Plus 4k 7bUID");
uint8_t SLmode = 0xff;
if (card.sak == 0x08) {
PrintAndLog("SAK: Mifare Plus 2k 7bUID");
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x18) {
PrintAndLog("SAK: Mifare Plus 4k 7bUID");
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x10) {
PrintAndLog("SAK: Mifare Plus 2k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x11) {
PrintAndLog("SAK: Mifare Plus 4k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x20) {
PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire");
if (card.ats_len > 0) {
SLmode = 3;
// check SL0
uint8_t data[250] = {0};
int datalen = 0;
// https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L161
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen);
if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0;
}
}
}
if (SLmode != 0xff)
PrintAndLog("Mifare Plus SL mode: SL%d", SLmode);
else
PrintAndLog("Mifare Plus SL mode: unknown(");
} else {
PrintAndLog("Mifare Plus info not available.");
}
DropField();
return 0;
}
int CmdHFMFPWritePerso(const char *cmd) {
uint8_t keyNum[64] = {0};
int keyNumLen = 0;
uint8_t key[64] = {0};
int keyLen = 0;
CLIParserInit("hf mfp wrp",
"Executes Write Perso command. Can be used in SL0 mode only.",
"Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
"\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_str1(NULL, NULL, "<HEX key number (2b)>", NULL),
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyNum, &keyNumLen);
CLIGetHexWithReturn(3, key, &keyLen);
CLIParserFree();
mfpSetVerboseMode(verbose);
if (!keyLen) {
memmove(key, DefaultKey, 16);
keyLen = 16;
}
if (keyNumLen != 2) {
PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen);
return 1;
}
if (keyLen != 16) {
PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
return 1;
}
uint8_t data[250] = {0};
int datalen = 0;
int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen);
if (res) {
PrintAndLog("Exchange error: %d", res);
return res;
}
if (datalen != 3) {
PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
return 1;
}
if (data[0] != 0x90) {
PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
return 1;
}
PrintAndLog("Write OK.");
return 0;
}
uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
int CmdHFMFPInitPerso(const char *cmd) {
int res;
uint8_t key[256] = {0};
int keyLen = 0;
uint8_t keyNum[2] = {0};
uint8_t data[250] = {0};
int datalen = 0;
CLIParserInit("hf mfp initp",
"Executes Write Perso command for all card's keys. Can be used in SL0 mode only.",
"Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
"\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
void* argtable[] = {
arg_param_begin,
arg_litn("vV", "verbose", 0, 2, "show internal data."),
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1;
CLIGetHexWithReturn(2, key, &keyLen);
CLIParserFree();
if (keyLen && keyLen != 16) {
PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
return 1;
}
if (!keyLen)
memmove(key, DefaultKey, 16);
mfpSetVerboseMode(verbose2);
for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
keyNum[0] = sn >> 8;
keyNum[1] = sn & 0xff;
res = MFPWritePerso(keyNum, key, (sn == 0x4000), true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLog("2k card detected.");
break;
}
if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLog("Write error on address %04x", sn);
break;
}
}
mfpSetVerboseMode(verbose);
for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
keyNum[0] = CardAddresses[i] >> 8;
keyNum[1] = CardAddresses[i] & 0xff;
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLog("Skipped[%04x]...", CardAddresses[i]);
} else {
if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLog("Write error on address %04x", CardAddresses[i]);
break;
}
}
}
DropField();
if (res)
return res;
PrintAndLog("Done.");
return 0;
}
int CmdHFMFPCommitPerso(const char *cmd) {
CLIParserInit("hf mfp commitp",
"Executes Commit Perso command. Can be used in SL0 mode only.",
"Usage:\n\thf mfp commitp -> \n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_int0(NULL, NULL, "SL mode", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIParserFree();
mfpSetVerboseMode(verbose);
uint8_t data[250] = {0};
int datalen = 0;
int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen);
if (res) {
PrintAndLog("Exchange error: %d", res);
return res;
}
if (datalen != 3) {
PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
return 1;
}
if (data[0] != 0x90) {
PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
return 1;
}
PrintAndLog("Switch level OK.");
return 0;
}
int CmdHFMFPAuth(const char *cmd) {
uint8_t keyn[250] = {0};
int keynlen = 0;
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp auth",
"Executes AES authentication command for Mifare Plus card",
"Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
"\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_str1(NULL, NULL, "<Key Num (HEX 2 bytes)>", NULL),
arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyn, &keynlen);
CLIGetHexWithReturn(3, key, &keylen);
CLIParserFree();
if (keynlen != 2) {
PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
return MifareAuth4(NULL, keyn, key, true, false, verbose);
}
int CmdHFMFPRdbl(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp rdbl",
"Reads several blocks from Mifare Plus card.",
"Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
"\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_int0("nN", "count", "blocks count (by default 1).", NULL),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_lit0("pP", "plain", "plain communication mode between reader and card."),
arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
int blocksCount = arg_get_int_def(2, 1);
bool keyB = arg_get_lit(3);
int plain = arg_get_lit(4);
uint32_t blockn = arg_get_int(5);
CLIGetHexWithReturn(6, key, &keylen);
CLIParserFree();
mfpSetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (blockn > 255) {
PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockn);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
// 3 blocks - wo iso14443-4 chaining
if (blocksCount > 3) {
PrintAndLog("ERROR: blocks count must be less than 3 instead of: %d", blocksCount);
return 1;
}
if (blocksCount > 1 && mfIsSectorTrailer(blockn)) {
PrintAndLog("WARNING: trailer!");
}
uint8_t sectorNum = mfSectorNum(blockn & 0xff);
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
res = MFPReadBlock(&session, plain, blockn & 0xff, blocksCount, false, false, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Read error: %d", res);
return res;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
return 6;
}
if (datalen != 1 + blocksCount * 16 + 8 + 2) {
PrintAndLog("Error return length:%d", datalen);
return 5;
}
int indx = blockn;
for(int i = 0; i < blocksCount; i++) {
PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16));
indx++;
if (mfIsSectorTrailer(indx) && i != blocksCount - 1){
PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx);
indx++;
}
}
if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) {
PrintAndLog("WARNING: mac not equal...");
PrintAndLog("MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
}
return 0;
}
int CmdHFMFPRdsc(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp rdsc",
"Reads one sector from Mifare Plus card.",
"Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
"\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_lit0("pP", "plain", "plain communication mode between reader and card."),
arg_int1(NULL, NULL, "<Sector Num (0..255)>", NULL),
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2);
bool plain = arg_get_lit(3);
uint32_t sectorNum = arg_get_int(4);
CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree();
mfpSetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (sectorNum > 39) {
PrintAndLog("ERROR: <Sector Num> must be in range [0..39] instead of: %d", sectorNum);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
for(int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) {
res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Read error: %d", res);
DropField();
return res;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
DropField();
return 6;
}
if (datalen != 1 + 16 + 8 + 2) {
PrintAndLog("Error return length:%d", datalen);
DropField();
return 5;
}
PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16));
if (memcmp(&data[1 + 16], mac, 8)) {
PrintAndLog("WARNING: mac on block %d not equal...", n);
PrintAndLog("MAC card: %s", sprint_hex(&data[1 + 16], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[1 + 16], 8));
}
}
DropField();
return 0;
}
int CmdHFMFPWrbl(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
uint8_t datain[250] = {0};
int datainlen = 0;
CLIParserInit("hf mfp wrbl",
"Writes one block to Mifare Plus card.",
"Usage:\n\thf mfp wrbl 1 ff0000000000000000000000000000ff 000102030405060708090a0b0c0d0e0f -> writes block 1 data\n"
"\thf mfp wrbl 2 ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
arg_str1(NULL, NULL, "<Data (HEX 16 bytes)>", NULL),
arg_str0(NULL, NULL, "<Key (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2);
uint32_t blockNum = arg_get_int(3);
CLIGetHexWithReturn(4, datain, &datainlen);
CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree();
mfpSetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (blockNum > 39) {
PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockNum);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key> must be 16 bytes long instead of: %d", keylen);
return 1;
}
if (datainlen != 16) {
PrintAndLog("ERROR: <Data> must be 16 bytes long instead of: %d", datainlen);
return 1;
}
uint8_t sectorNum = mfSectorNum(blockNum & 0xff);
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
res = MFPWriteBlock(&session, blockNum & 0xff, datain, false, false, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Write error: %d", res);
DropField();
return res;
}
if (datalen != 3 && (datalen != 3 + 8)) {
PrintAndLog("Error return length:%d", datalen);
DropField();
return 5;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
DropField();
return 6;
}
if (memcmp(&data[1], mac, 8)) {
PrintAndLog("WARNING: mac not equal...");
PrintAndLog("MAC card: %s", sprint_hex(&data[1], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[1], 8));
}
DropField();
PrintAndLog("Write OK.");
return 0;
}
int CmdHFMFPMAD(const char *cmd) {
CLIParserInit("hf mfp mad",
"Checks and prints Mifare Application Directory (MAD)",
"Usage:\n\thf mfp mad -> shows MAD if exists\n"
"\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n");
void *argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show technical data"),
arg_str0("aA", "aid", "print all sectors with aid", NULL),
arg_str0("kK", "key", "key for printing sectors", NULL),
arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[16] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
CLIParserFree();
if (aidlen != 2 && keylen > 0) {
PrintAndLogEx(WARNING, "do not need a key without aid.");
}
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
if (verbose) {
for (int i = 0; i < 4; i ++)
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(&sector0[i * 16], 16));
}
bool haveMAD2 = false;
MAD1DecodeAndPrint(sector0, verbose, &haveMAD2);
if (haveMAD2) {
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
MAD2DecodeAndPrint(sector10, verbose);
}
if (aidlen == 2) {
uint16_t aaid = (aid[0] << 8) + aid[1];
PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid);
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, sector10, mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
uint8_t akey[16] = {0};
memcpy(akey, g_mifarep_ndef_key, 16);
if (keylen == 16) {
memcpy(akey, key, 16);
}
for (int i = 0; i < madlen; i++) {
if (aaid == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector, false)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
for (int j = 0; j < (verbose ? 4 : 3); j ++)
PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16));
}
}
}
return 0;
}
int CmdHFMFPNDEF(const char *cmd) {
CLIParserInit("hf mfp ndef",
"Prints NFC Data Exchange Format (NDEF)",
"Usage:\n\thf mfp ndef -> shows NDEF data\n"
"\thf mfp ndef -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key\n");
void *argtable[] = {
arg_param_begin,
arg_litn("vV", "verbose", 0, 2, "show technical data"),
arg_str0("aA", "aid", "replace default aid for NDEF", NULL),
arg_str0("kK", "key", "replace default key for NDEF", NULL),
arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1;
uint8_t aid[2] = {0};
int aidlen;
CLIGetHexWithReturn(2, aid, &aidlen);
uint8_t key[16] = {0};
int keylen;
CLIGetHexWithReturn(3, key, &keylen);
bool keyB = arg_get_lit(4);
CLIParserFree();
uint16_t ndefAID = 0x03e1;
if (aidlen == 2)
ndefAID = (aid[0] << 8) + aid[1];
uint8_t ndefkey[16] = {0};
memcpy(ndefkey, g_mifarep_ndef_key, 16);
if (keylen == 16) {
memcpy(ndefkey, key, 16);
}
uint8_t sector0[16 * 4] = {0};
uint8_t sector10[16 * 4] = {0};
uint8_t data[4096] = {0};
int datalen = 0;
PrintAndLogEx(NORMAL, "");
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) {
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
bool haveMAD2 = false;
int res = MADCheck(sector0, NULL, verbose, &haveMAD2);
if (res) {
PrintAndLogEx(ERR, "MAD error %d.", res);
return res;
}
if (haveMAD2) {
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
return 2;
}
}
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) {
PrintAndLogEx(ERR, "can't decode mad.");
return 10;
}
printf("data reading:");
for (int i = 0; i < madlen; i++) {
if (ndefAID == mad[i]) {
uint8_t vsector[16 * 4] = {0};
if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector, false)) {
PrintAndLogEx(ERR, "read sector %d error.", i + 1);
return 2;
}
memcpy(&data[datalen], vsector, 16 * 3);
datalen += 16 * 3;
printf(".");
}
}
printf(" OK\n");
if (!datalen) {
PrintAndLogEx(ERR, "no NDEF data.");
return 11;
}
if (verbose2) {
PrintAndLogEx(NORMAL, "NDEF data:");
dump_buffer(data, datalen, stdout, 1);
}
NDEFDecodeAndPrint(data, datalen, verbose);
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"},
{"wrp", CmdHFMFPWritePerso, 0, "Write Perso command"},
{"initp", CmdHFMFPInitPerso, 0, "Fills all the card's keys"},
{"commitp", CmdHFMFPCommitPerso, 0, "Move card to SL1 or SL3 mode"},
{"auth", CmdHFMFPAuth, 0, "Authentication"},
{"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
{"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"},
{"ndef", CmdHFMFPNDEF, 0, "Prints NDEF records from card"},
{NULL, NULL, 0, NULL}
};
int CmdHFMFP(const char *Cmd) {
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable);
return 0;
}

18
client/cmdhfmfp.h Normal file
View file

@ -0,0 +1,18 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Plus commands
//-----------------------------------------------------------------------------
#ifndef CMDHFMFP_H__
#define CMDHFMFP_H__
#include "mifare/mifaredefault.h"
extern int CmdHFMFP(const char *Cmd);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,54 +1,10 @@
#include "cmdhfmf.h"
#include "cmdhf14a.h"
#ifndef CMDHFMFU_H__
#define CMDHFMFU_H__
int CmdHF14AMfUWrBl(const char *Cmd);
int CmdHF14AMfURdBl(const char *Cmd);
#include <stdint.h>
//Crypto Cards
int CmdHF14AMfucAuth(const char *Cmd);
//general stuff
int CmdHF14AMfUDump(const char *Cmd);
int CmdHF14AMfUInfo(const char *Cmd);
uint32_t GetHF14AMfU_Type(void);
int ul_print_type(uint32_t tagtype, uint8_t spacer);
int usage_hf_mfu_dump(void);
int usage_hf_mfu_info(void);
int usage_hf_mfu_rdbl(void);
int usage_hf_mfu_wrbl(void);
int CmdHFMFUltra(const char *Cmd);
typedef enum TAGTYPE_UL {
UNKNOWN = 0x000000,
UL = 0x000001,
UL_C = 0x000002,
UL_EV1_48 = 0x000004,
UL_EV1_128 = 0x000008,
NTAG = 0x000010,
NTAG_203 = 0x000020,
NTAG_210 = 0x000040,
NTAG_212 = 0x000080,
NTAG_213 = 0x000100,
NTAG_215 = 0x000200,
NTAG_216 = 0x000400,
MY_D = 0x000800,
MY_D_NFC = 0x001000,
MY_D_MOVE = 0x002000,
MY_D_MOVE_NFC = 0x004000,
MY_D_MOVE_LEAN= 0x008000,
NTAG_I2C_1K = 0x010000,
NTAG_I2C_2K = 0x020000,
FUDAN_UL = 0x040000,
MAGIC = 0x080000,
UL_MAGIC = UL | MAGIC,
UL_C_MAGIC = UL_C | MAGIC,
UL_ERROR = 0xFFFFFF,
} TagTypeUL_t;
extern int CmdHFMFUltra(const char *Cmd);
extern uint32_t GetHF14AMfU_Type(void);
extern int ul_print_type(uint32_t tagtype, uint8_t spacer);
#endif

View file

@ -22,6 +22,7 @@
#include "comms.h"
#include "iso14443crc.h"
#include "protocols.h"
#include "taginfo.h"
#define TOPAZ_STATIC_MEMORY (0x0f * 8) // 15 blocks with 8 Bytes each
@ -477,7 +478,7 @@ int CmdHFTopazReader(const char *Cmd)
topaz_tag.uid[0]);
PrintAndLog(" UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s",
topaz_tag.uid[6],
getTagInfo(topaz_tag.uid[6]));
getManufacturerName(topaz_tag.uid[6]));
memcpy(topaz_tag.data_blocks, rall_response+2, 0x0f*8);
PrintAndLog("");

View file

@ -20,7 +20,8 @@
#include "cmdmain.h"
#include "cmddata.h"
/* low-level hardware control */
static uint32_t hw_capabilities = 0;
static int CmdHelp(const char *Cmd);
@ -334,10 +335,10 @@ int CmdFPGAOff(const char *Cmd)
int CmdLCD(const char *Cmd)
{
int i, j;
unsigned int i, j;
UsbCommand c={CMD_LCD};
sscanf(Cmd, "%x %d", &i, &j);
sscanf(Cmd, "%x %u", &i, &j);
while (j--) {
c.arg[0] = i & 0x1ff;
SendCommand(&c);
@ -403,6 +404,10 @@ int CmdTune(const char *Cmd)
return CmdTuneSamples(Cmd);
}
bool PM3hasSmartcardSlot(void) {
return (hw_capabilities & HAS_SMARTCARD_SLOT);
}
int CmdVersion(const char *Cmd)
{
@ -415,6 +420,7 @@ int CmdVersion(const char *Cmd)
PrintAndLog("Prox/RFID mark3 RFID instrument");
PrintAndLog((char*)resp.d.asBytes);
lookupChipID(resp.arg[0], resp.arg[1]);
hw_capabilities = resp.arg[2];
}
return 0;
}

View file

@ -11,6 +11,8 @@
#ifndef CMDHW_H__
#define CMDHW_H__
#include <stdbool.h>
int CmdHW(const char *Cmd);
int CmdDetectReader(const char *Cmd);
@ -23,5 +25,6 @@ int CmdSetDivisor(const char *Cmd);
int CmdSetMux(const char *Cmd);
int CmdTune(const char *Cmd);
int CmdVersion(const char *Cmd);
bool PM3hasSmartcardSlot(void);
#endif

View file

@ -227,11 +227,12 @@ int usage_lf_config(void)
PrintAndLog(" h This help");
PrintAndLog(" L Low frequency (125 KHz)");
PrintAndLog(" H High frequency (134 KHz)");
PrintAndLog(" q <divisor> Manually set divisor. 88-> 134KHz, 95-> 125 Hz");
PrintAndLog(" q <divisor> Manually set divisor. 88-> 134 KHz, 95-> 125 KHz");
PrintAndLog(" b <bps> Sets resolution of bits per sample. Default (max): 8");
PrintAndLog(" d <decim> Sets decimation. A value of N saves only 1 in N samples. Default: 1");
PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1");
PrintAndLog(" t <threshold> Sets trigger threshold. 0 means no threshold (range: 0-128)");
PrintAndLog(" s <smplstoskip> Sets a number of samples to skip before capture. Default: 0");
PrintAndLog("Examples:");
PrintAndLog(" lf config b 8 L");
PrintAndLog(" Samples at 125KHz, 8bps.");
@ -255,6 +256,7 @@ int CmdLFSetConfig(const char *Cmd)
bool errors = false;
int trigger_threshold =-1;//Means no change
uint8_t unsigned_trigg = 0;
int samples_to_skip = -1;
uint8_t cmdp =0;
while(param_getchar(Cmd, cmdp) != 0x00)
@ -295,6 +297,10 @@ int CmdLFSetConfig(const char *Cmd)
averaging = param_getchar(Cmd,cmdp+1) == '1';
cmdp+=2;
break;
case 's':
samples_to_skip = param_get32ex(Cmd,cmdp+1,0,10);
cmdp+=2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = 1;
@ -316,7 +322,7 @@ int CmdLFSetConfig(const char *Cmd)
if(bps >> 4) bps = 8;
sample_config config = {
decimation,bps,averaging,divisor,trigger_threshold
decimation,bps,averaging,divisor,trigger_threshold,samples_to_skip
};
//Averaging is a flag on high-bit of arg[1]
UsbCommand c = {CMD_SET_LF_SAMPLING_CONFIG};
@ -937,8 +943,8 @@ int CmdLFfind(const char *Cmd)
PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n");
return 1;
}
ans=CmdLFHitagReader("26"); // 26 = RHT2F_UID_ONLY
if (ans==0) {
if (getHitagUid(NULL, true)) {
PrintAndLog("\nValid Hitag2 tag Found!");
return 1;
}
ans = CmdCOTAGRead("");

View file

@ -1161,6 +1161,119 @@ int CmdEM4x05WriteWord(const char *Cmd) {
return EM4x05WriteWord(addr, data, pwd, usePwd, swap, invert);
}
int usage_lf_em_protect(void) {
PrintAndLog("Protect EM4x05. Tag must be on antenna. ");
PrintAndLog("");
PrintAndLog("Usage: lf em 4x05protect [h] d <data> p <pwd> [s] [i]");
PrintAndLog("Options:");
PrintAndLog(" h - this help");
PrintAndLog(" d <data> - data to write (hex)");
PrintAndLog(" p <pwd> - password (hex) (optional)");
PrintAndLog(" s - swap the data bit order before write");
PrintAndLog(" i - invert the data bits before write");
PrintAndLog("samples:");
PrintAndLog(" lf em 4x05protect d 11223344");
PrintAndLog(" lf em 4x05protect p deadc0de d 11223344 s i");
return 0;
}
int EM4x05Protect(uint32_t data, uint32_t pwd, bool usePwd, bool swap, bool invert) {
if (swap) data = SwapBits(data, 32);
if (invert) data ^= 0xFFFFFFFF;
if ( !usePwd ) {
PrintAndLog("Writing Protect data %08X", data);
} else {
PrintAndLog("Writing Protect data %08X using password %08X", data, pwd);
}
uint16_t flag = usePwd;
UsbCommand c = {CMD_EM4X_PROTECT, {flag, data, pwd}};
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
PrintAndLog("Error occurred, device did not respond during protect operation.");
return -1;
}
if ( !downloadSamplesEM() ) {
return -1;
}
//check response for 00001010 for write confirmation!
//attempt demod:
uint32_t dummy = 0;
int result = demodEM4x05resp(&dummy,false);
if (result == 1) {
PrintAndLog("Protect Verified");
} else {
PrintAndLog("Protect could not be verified");
}
return result;
}
int CmdEM4x05ProtectWrite(const char *Cmd) {
bool errors = false;
bool usePwd = false;
uint32_t data = 0xFFFFFFFF;
uint32_t pwd = 0xFFFFFFFF;
bool swap = false;
bool invert = false;
bool gotData = false;
char cmdp = 0;
while(param_getchar(Cmd, cmdp) != 0x00)
{
switch(param_getchar(Cmd, cmdp))
{
case 'h':
case 'H':
return usage_lf_em_write();
case 'd':
case 'D':
data = param_get32ex(Cmd, cmdp+1, 0, 16);
gotData = true;
cmdp += 2;
break;
case 'i':
case 'I':
invert = true;
cmdp++;
break;
case 'p':
case 'P':
pwd = param_get32ex(Cmd, cmdp+1, 1, 16);
if (pwd == 1) {
PrintAndLog("invalid pwd");
errors = true;
}
usePwd = true;
cmdp += 2;
break;
case 's':
case 'S':
swap = true;
cmdp++;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
if(errors) break;
}
//Validations
if(errors) return usage_lf_em_protect();
if ( strlen(Cmd) == 0 ) return usage_lf_em_protect();
if (!gotData) {
PrintAndLog("You must enter the data you want to write");
return usage_lf_em_protect();
}
return EM4x05Protect(data, pwd, usePwd, swap, invert);
}
void printEM4x05config(uint32_t wordData) {
uint16_t datarate = EM4x05_GET_BITRATE(wordData);
uint8_t encoder = ((wordData >> 6) & 0xF);
@ -1345,6 +1458,7 @@ static command_t CommandTable[] =
{"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"},
{"4x05readword", CmdEM4x05ReadWord, 0, "<Word> (pwd) -- Read EM4x05/EM4x69 word data"},
{"4x05writeword", CmdEM4x05WriteWord, 0, "<Word> <data> (pwd) -- Write EM4x05/EM4x69 word data"},
{"4x05protect", CmdEM4x05ProtectWrite, 0, "<data> (pwd) -- Write Protection to EM4x05"},
{"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"},
{NULL, NULL, 0, NULL}
};

View file

@ -137,7 +137,7 @@ int CmdFdxDemod(const char *Cmd){
//Differential Biphase / di-phase (inverted biphase)
//get binary from ask wave
if (!ASKbiphaseDemod("0 32 1 0", false)) {
if (!ASKbiphaseDemod("0 32 1 100", false)) {
if (g_debugMode) PrintAndLog("DEBUG: Error - FDX-B ASKbiphaseDemod failed");
return 0;
}
@ -206,7 +206,7 @@ int CmdFdxDemod(const char *Cmd){
}
int CmdFdxRead(const char *Cmd) {
lf_read(true, 10000);
lf_read(true, 39999);
return CmdFdxDemod(Cmd);
}

View file

@ -39,7 +39,7 @@
*
* Returns the number of nibbles (4 bits) entered.
*/
int hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) {
int hid_hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) {
// TODO: Replace this with param_gethex when it supports arbitrary length
// inputs.
int n = 0, i = 0;
@ -201,7 +201,7 @@ int CmdHIDReadFSK(const char *Cmd)
int CmdHIDSim(const char *Cmd)
{
uint32_t hi2 = 0, hi = 0, lo = 0;
hexstring_to_int96(&hi2, &hi, &lo, Cmd);
hid_hexstring_to_int96(&hi2, &hi, &lo, Cmd);
if (hi2 != 0) {
PrintAndLog("Emulating tag with ID %x%08x%08x", hi2, hi, lo);
} else {
@ -218,7 +218,7 @@ int CmdHIDSim(const char *Cmd)
int CmdHIDClone(const char *Cmd)
{
unsigned int top = 0, mid = 0, bot = 0;
hexstring_to_int96(&top, &mid, &bot, Cmd);
hid_hexstring_to_int96(&top, &mid, &bot, Cmd);
hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
Write(&packed);
return 0;
@ -234,7 +234,7 @@ int CmdHIDDecode(const char *Cmd){
uint32_t top = 0, mid = 0, bot = 0;
bool ignoreParity = false;
hexstring_to_int96(&top, &mid, &bot, Cmd);
hid_hexstring_to_int96(&top, &mid, &bot, Cmd);
hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
char opt = param_getchar(Cmd, 1);

View file

@ -22,4 +22,6 @@ int CmdHIDClone(const char *Cmd);
int CmdHIDDecode(const char *Cmd);
int CmdHIDEncode(const char *Cmd);
int CmdHIDWrite(const char *Cmd);
// This is used by the Paradox code
int hid_hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str);
#endif

View file

@ -19,20 +19,16 @@
#include "common.h"
#include "util.h"
#include "parity.h"
#include "hitag2.h"
#include "hitagS.h"
#include "hitag.h"
#include "cmdmain.h"
static int CmdHelp(const char *Cmd);
size_t nbytes(size_t nbits) {
static size_t nbytes(size_t nbits) {
return (nbits/8) + ((nbits%8)>0);
}
int CmdLFHitagList(const char *Cmd)
{
uint8_t *got = malloc(USB_CMD_DATA_SIZE);
static int CmdLFHitagList(const char *Cmd) {
uint8_t *got = malloc(USB_CMD_DATA_SIZE);
// Query for the actual size of the trace
UsbCommand response;
GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false);
@ -52,6 +48,7 @@ int CmdLFHitagList(const char *Cmd)
PrintAndLog(" ETU :nbits: who bytes");
PrintAndLog("---------+-----+----+-----------");
int j;
int i = 0;
int prev = -1;
int len = strlen(Cmd);
@ -73,7 +70,7 @@ int CmdLFHitagList(const char *Cmd)
for (;;) {
if(i > traceLen) { break; }
if(i >= traceLen) { break; }
bool isResponse;
int timestamp = *((uint32_t *)(got+i));
@ -93,7 +90,7 @@ int CmdLFHitagList(const char *Cmd)
// or each half bit period in 256 levels.
int bits = got[i+8];
int len = nbytes(got[i+8]);
int len = nbytes(bits);
if (len > 100) {
break;
@ -101,19 +98,43 @@ int CmdLFHitagList(const char *Cmd)
if (i + len > traceLen) { break;}
uint8_t *frame = (got+i+9);
/*
int fillupBits = 8 - (bits % 8);
byte_t framefilled[bits+fillupBits];
byte_t* ff = framefilled;
int response_bit[200] = {0};
int z = 0;
for (int y = 0; y < len; y++) {
for (j = 0; j < 8; j++) {
response_bit[z] = 0;
if ((frame[y] & ((mask << 7) >> j)) != 0)
response_bit[z] = 1;
z++;
}
}
z = 0;
for (int y = 0; y < len; y++) {
ff[y] = (response_bit[z] << 7) | (response_bit[z + 1] << 6)
| (response_bit[z + 2] << 5) | (response_bit[z + 3] << 4)
| (response_bit[z + 4] << 3) | (response_bit[z + 5] << 2)
| (response_bit[z + 6] << 1) | response_bit[z + 7];
z += 8;
}
*/
// Break and stick with current result if buffer was not completely full
if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
char line[1000] = "";
int j;
for (j = 0; j < len; j++) {
//if((parityBits >> (len - j - 1)) & 0x01) {
if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) {
sprintf(line+(j*4), "%02x! ", frame[j]);
}
else {
} else {
sprintf(line+(j*4), "%02x ", frame[j]);
}
}
@ -145,13 +166,15 @@ int CmdLFHitagList(const char *Cmd)
return 0;
}
int CmdLFHitagSnoop(const char *Cmd) {
static int CmdLFHitagSnoop(const char *Cmd) {
UsbCommand c = {CMD_SNOOP_HITAG};
SendCommand(&c);
return 0;
}
int CmdLFHitagSim(const char *Cmd) {
static int CmdLFHitagSim(const char *Cmd) {
UsbCommand c = {CMD_SIMULATE_HITAG};
char filename[FILE_PATH_SIZE] = { 0x00 };
@ -184,20 +207,82 @@ int CmdLFHitagSim(const char *Cmd) {
return 0;
}
bool getHitagUid(uint32_t *uid, bool quiet) {
// ToDo: this is for Hitag2 only (??)
UsbCommand c = {CMD_READER_HITAG, {RHT2F_UID_ONLY}};
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
if (!quiet) PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return false;
}
if (resp.arg[0] == false) {
if (!quiet) PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
return false;
}
if (uid)
*uid = bytes_to_num(resp.d.asBytes, 4);
return true;
}
static int CmdLFHitagInfo(const char *Cmd) {
char ctmp = param_getchar(Cmd, 0);
if (ctmp != '\0') {
PrintAndLog("Usage: lf hitag info [h]");
PrintAndLog("Options:");
PrintAndLog(" h This help");
PrintAndLog("Examples:");
PrintAndLog(" lf hitag info");
return 0;
}
// read UID
uint32_t uid = 0;
if (getHitagUid(&uid, false) == false)
return 1;
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
// how to detemine Hitag types?
// read block3, get configuration byte.
// PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
// common configurations.
// printHitagConfiguration(0x06);
//printHitagConfiguration( 0x0E );
//printHitagConfiguration( 0x02 );
//printHitagConfiguration( 0x00 );
//printHitagConfiguration( 0x04 );
return 0;
}
int CmdLFHitagReader(const char *Cmd) {
UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}};
UsbCommand c = {CMD_READER_HITAG};
hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd, 0, 0, 10);
switch (htf) {
case 01: { //RHTSF_CHALLENGE
case RHTSF_CHALLENGE: {
c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode
} break;
case 02: { //RHTSF_KEY
case RHTSF_KEY: {
c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode
} break;
case RHT2F_PASSWORD: {
num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
@ -221,11 +306,13 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog("");
PrintAndLog("Usage: hitag reader <Reader Function #>");
PrintAndLog("Reader Functions:");
PrintAndLog(" HitagS (0*)");
PrintAndLog(" 01 <nr> <ar> (Challenge) read all pages from a Hitag S tag");
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) read all pages from a Hitag S tag");
PrintAndLog(" Hitag1 (1*)");
PrintAndLog(" Hitag2 (2*)");
PrintAndLog(" HitagS (0*):");
PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)");
PrintAndLog(" Hitag1 (1*):");
PrintAndLog(" (not yet implemented)");
PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 21 <password> (password mode)");
PrintAndLog(" 22 <nr> <ar> (authentication)");
PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low");
@ -243,16 +330,22 @@ int CmdLFHitagReader(const char *Cmd) {
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1;
if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return 1;
}
uint32_t id = bytes_to_num(resp.d.asBytes, 4);
if (htf == RHT2F_UID_ONLY){
PrintAndLog("Valid Hitag2 tag found - UID: %08x", id);
} else {
if (htf != RHT2F_UID_ONLY) {
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
char filename[256];
FILE* pf = NULL;
@ -269,12 +362,11 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog("Succesfully saved tag memory to [%s]",filename);
}
return 0;
}
int CmdLFHitagSimS(const char *Cmd) {
static int CmdLFHitagSimS(const char *Cmd) {
UsbCommand c = { CMD_SIMULATE_HITAG_S };
char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf;
@ -307,7 +399,8 @@ int CmdLFHitagSimS(const char *Cmd) {
return 0;
}
int CmdLFHitagCheckChallenges(const char *Cmd) {
static int CmdLFHitagCheckChallenges(const char *Cmd) {
UsbCommand c = { CMD_TEST_HITAGS_TRACES };
char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf;
@ -334,39 +427,45 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
//file with all the challenges to try
c.arg[0] = (uint32_t)file_given;
c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode
SendCommand(&c);
return 0;
}
int CmdLFHitagWP(const char *Cmd) {
static int CmdLFHitagWriter(const char *Cmd) {
UsbCommand c = { CMD_WR_HITAG_S };
hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10);
switch (htf) {
case 03: { //WHTSF_CHALLENGE
case WHTSF_CHALLENGE: {
num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
} break;
case 04:
case 24:
{ //WHTSF_KEY
case WHTSF_KEY:
case WHT2F_CRYPTO: {
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
} break;
case WHT2F_PASSWORD: {
num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
c.arg[2] = param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd, 3, 0, 16), 4, htd->crypto.data);
} break;
default: {
PrintAndLog("Error: unkown writer function %d",htf);
PrintAndLog("Hitag writer functions");
PrintAndLog(" HitagS (0*)");
PrintAndLog(" HitagS (0*):");
PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" Hitag1 (1*)");
PrintAndLog(" Hitag2 (2*)");
PrintAndLog(" (not yet implemented)");
PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 27 <password> <page> <byte0...byte3> write page on a Hitag2 tag");
return 1;
} break;
}
@ -377,35 +476,44 @@ int CmdLFHitagWP(const char *Cmd) {
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1;
if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
return 1;
}
return 0;
}
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"list", CmdLFHitagList, 1, "<outfile> List Hitag trace history"},
{"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"},
{"sim", CmdLFHitagSim, 1, "<infile> Simulate Hitag transponder"},
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" },
{"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" },
{"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> test all challenges" }, {
NULL,NULL, 0, NULL }
{"list", CmdLFHitagList, 0, "<outfile> List Hitag trace history"},
{"info", CmdLFHitagInfo, 0, "Tag information" },
{"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"},
{"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"},
{"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" },
{"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" },
{"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" },
{ NULL, NULL, 0, NULL }
};
int CmdLFHitag(const char *Cmd)
{
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd)
{
static int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable);
return 0;
}
int CmdLFHitag(const char *Cmd) {
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -11,11 +11,11 @@
#ifndef CMDLFHITAG_H__
#define CMDLFHITAG_H__
int CmdLFHitag(const char *Cmd);
#include <stdint.h>
#include <stdbool.h>
int CmdLFHitagList(const char *Cmd);
int CmdLFHitagSnoop(const char *Cmd);
int CmdLFHitagSim(const char *Cmd);
int CmdLFHitagReader(const char *Cmd);
extern int CmdLFHitag(const char *Cmd);
extern int CmdLFHitagReader(const char *Cmd);
extern bool getHitagUid(uint32_t *uid, bool quiet);
#endif

View file

@ -19,7 +19,14 @@
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h"
#include "comms.h"
// This card type is similar to HID, so we include the utils from there
#include "cmdlfhid.h"
#include "hidcardformats.h"
#include "hidcardformatutils.h"
static int CmdHelp(const char *Cmd);
void ParadoxWrite(hidproxmessage_t *packed);
//by marshmellow
//Paradox Prox demod - FSK RF/50 with preamble of 00001111 (then manchester encoded)
@ -55,14 +62,24 @@ int CmdFSKdemodParadox(const char *Cmd)
if (g_debugMode) PrintAndLog("DEBUG: Error - no value found");
return 0;
}
uint32_t fc = ((hi & 0x3)<<6) | (lo>>26);
uint32_t cardnum = (lo>>10)&0xFFFF;
uint32_t rawLo = bytebits_to_byte(BitStream+idx+64,32);
uint32_t rawHi = bytebits_to_byte(BitStream+idx+32,32);
uint32_t rawHi2 = bytebits_to_byte(BitStream+idx,32);
PrintAndLog("Paradox TAG ID: %x%08x - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x",
hi>>10, (hi & 0x3)<<26 | (lo>>10), fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo);
// Steal the HID parsing to output a "full" ID we can send to the HID cloning function
hidproxmessage_t packed = initialize_proxmessage_object(hi2, hi, lo);
if (packed.top != 0) {
PrintAndLog("Paradox TAG ID: %x%08x (Full ID: %x%08x%08x) - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x",
hi>>10, (hi & 0x3)<<26 | (lo>>10), (uint32_t)packed.top, (uint32_t)packed.mid, (uint32_t)packed.bot, fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo);
} else {
PrintAndLog("Paradox TAG ID: %x%08x (Full ID: %x%08x) - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x",
hi>>10, (hi & 0x3)<<26 | (lo>>10), (uint32_t)packed.mid, (uint32_t)packed.bot, fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo);
}
setDemodBuf(BitStream,BitLen,idx);
setClockGrid(50, waveIdx + (idx*50));
if (g_debugMode){
@ -80,10 +97,31 @@ int CmdParadoxRead(const char *Cmd) {
return CmdFSKdemodParadox(Cmd);
}
int CmdParadoxClone(const char *Cmd)
{
unsigned int top = 0, mid = 0, bot = 0;
hid_hexstring_to_int96(&top, &mid, &bot, Cmd);
hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
ParadoxWrite(&packed);
return 0;
}
void ParadoxWrite(hidproxmessage_t *packed){
UsbCommand c;
c.d.asBytes[0] = (packed->top != 0 && ((packed->mid & 0xFFFFFFC0) != 0))
? 1 : 0; // Writing long format?
c.cmd = CMD_PARADOX_CLONE_TAG;
c.arg[0] = (packed->top & 0x000FFFFF);
c.arg[1] = packed->mid;
c.arg[2] = packed->bot;
SendCommand(&c);
}
static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"},
{"demod", CmdFSKdemodParadox, 1, "Demodulate a Paradox FSK tag from the GraphBuffer"},
{"read", CmdParadoxRead, 0, "Attempt to read and Extract tag data from the antenna"},
{"clone", CmdParadoxClone, 0, "<ID> -- Clone Paradox to T55x7 (tag must be in antenna)"},
{NULL, NULL, 0, NULL}
};

View file

@ -1,6 +1,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 Chalk <chalk.secu at gmail.com>
// 2015 Dake <thomas.cayrou at gmail.com>
// 2018 sguerrini97 <sguerrini97 at gmail.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
@ -76,6 +77,21 @@ int usage_pcf7931_write(){
return 0;
}
int usage_pcf7931_bruteforce()
{
PrintAndLog("Usage: lf pcf7931 bruteforce [h] <start password> <tries>");
PrintAndLog("This command tries to disable PAC of a PCF7931 transponder by bruteforcing the password.");
PrintAndLog("!! THIS IS NOT INTENDED TO RECOVER THE FULL PASSWORD !!");
PrintAndLog("!! DO NOT USE UNLESS THE FIRST 5 BYTES OF THE PASSWORD ARE KNOWN !!");
PrintAndLog("Options:");
PrintAndLog(" h This help");
PrintAndLog(" start password hex password to start from");
PrintAndLog(" tries How many times to send the same data frame");
PrintAndLog("Examples:");
PrintAndLog(" lf pcf7931 bruteforce 00000000123456 3");
return 0;
}
int usage_pcf7931_config(){
PrintAndLog("Usage: lf pcf7931 config [h] [r] <pwd> <delay> <offset width> <offset position>");
PrintAndLog("This command tries to set the configuration used with PCF7931 commands");
@ -159,12 +175,47 @@ int CmdLFPCF7931Write(const char *Cmd){
return 0;
}
int CmdLFPCF7931BruteForce(const char *Cmd){
uint8_t ctmp = param_getchar(Cmd, 0);
if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce();
uint8_t start_password[7] = {0};
uint8_t tries = 3;
if (param_gethex(Cmd, 0, start_password, 14)) return usage_pcf7931_bruteforce();
if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce();
PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x",
start_password[0],
start_password[1],
start_password[2],
start_password[3],
start_password[4],
start_password[5],
start_password[6]);
PrintAndLog("Trying each password %d times", tries);
UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {bytes_to_num(start_password, 7), tries} };
c.d.asDwords[7] = (configPcf.OffsetWidth + 128);
c.d.asDwords[8] = (configPcf.OffsetPosition + 128);
c.d.asDwords[9] = configPcf.InitDelay;
clearCommandBuffer();
SendCommand(&c);
//no ack?
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"},
{"write", CmdLFPCF7931Write, 0, "Write data on a PCF7931 transponder."},
{"config", CmdLFPCF7931Config, 1, "Configure the password, the tags initialization delay and time offsets (optional)"},
{"bruteforce", CmdLFPCF7931BruteForce, 0, "Bruteforce a PCF7931 transponder password."},
{NULL, NULL, 0, NULL}
};

View file

@ -1,6 +1,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012 Chalk <chalk.secu at gmail.com>
// 2015 Dake <thomas.cayrou at gmail.com>
// 2018 sguerrini97 <sguerrini97 at gmail.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
@ -26,12 +27,14 @@ int pcf7931_printConfig();
int usage_pcf7931_read();
int usage_pcf7931_write();
int usage_pcf7931_bruteforce();
int usage_pcf7931_config();
int CmdLFPCF7931(const char *Cmd);
int CmdLFPCF7931Read(const char *Cmd);
int CmdLFPCF7931Write(const char *Cmd);
int CmdLFPCF7931BruteForce(const char *Cmd);
int CmdLFPCF7931Config(const char *Cmd);
#endif

View file

@ -23,8 +23,8 @@
#include "cmdlf.h"
#include "util.h"
#include "lfdemod.h"
#include "cmdhf14a.h" //for getTagInfo
#include "protocols.h"
#include "taginfo.h"
#define T55x7_CONFIGURATION_BLOCK 0x00
#define T55x7_PAGE0 0x00
@ -67,6 +67,8 @@ int usage_t55xx_read(){
PrintAndLog(" p <password> - OPTIONAL password (8 hex characters)");
PrintAndLog(" o - OPTIONAL override safety check");
PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0");
PrintAndLog(" r <mode> - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");
PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference");
PrintAndLog(" ****WARNING****");
PrintAndLog(" Use of read with password on a tag not configured for a pwd");
PrintAndLog(" can damage the tag");
@ -86,6 +88,8 @@ int usage_t55xx_write(){
PrintAndLog(" p <password> - OPTIONAL password 4bytes (8 hex characters)");
PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0");
PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****");
PrintAndLog(" r <mode> - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");
PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3");
@ -132,6 +136,8 @@ int usage_t55xx_detect(){
PrintAndLog("Options:");
PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag.");
PrintAndLog(" p <password> - OPTIONAL password (8 hex characters)");
PrintAndLog(" r <mode> - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference");
PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" lf t55xx detect");
@ -172,13 +178,16 @@ int usage_t55xx_bruteforce(){
PrintAndLog(" password must be 4 bytes (8 hex symbols)");
PrintAndLog("Options:");
PrintAndLog(" h - this help");
PrintAndLog(" r <mode> - OPTIONAL downlink encoding '0' fixed bit length (default)");
PrintAndLog(" '1' long leading reference, '2' leading zero ");
PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes");
PrintAndLog(" <start_pwd> - 4 byte hex value to start pwd search at");
PrintAndLog(" <end_pwd> - 4 byte hex value to end pwd search at");
PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>");
PrintAndLog("");
PrintAndLog("Examples:");
PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb");
PrintAndLog(" lf t55xx bruteforce i default_pwd.dic");
PrintAndLog(" lf t55xx bruteforce [r 2] aaaaaaaa bbbbbbbb");
PrintAndLog(" lf t55xx bruteforce [r 2] i default_pwd.dic");
PrintAndLog("");
return 0;
}
@ -311,12 +320,12 @@ int CmdT55xxSetConfig(const char *Cmd) {
return printConfiguration ( config);
}
int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){
int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){
//Password mode
if ( usepwd ) {
// try reading the config block and verify that PWD bit is set before doing this!
if ( !override ) {
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0;
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0;
if ( !tryDetectModulation() ) {
PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits.");
return 0;
@ -330,7 +339,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32
}
}
if (!AquireData(page1, block, usepwd, password) ) return 0;
if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0;
if (!DecodeT55xxBlock()) return 0;
char blk[10]={0};
@ -342,6 +351,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32
int CmdT55xxReadBlock(const char *Cmd) {
uint8_t block = REGULAR_READ_MODE_BLOCK;
uint32_t password = 0; //default to blank Block 7
uint8_t downlink_mode = 0;
bool usepwd = false;
bool override = false;
bool page1 = false;
@ -372,6 +383,12 @@ int CmdT55xxReadBlock(const char *Cmd) {
page1 = true;
cmdp++;
break;
case 'r':
case 'R':
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
if (downlink_mode > 3) downlink_mode = 0;
cmdp +=2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -386,7 +403,7 @@ int CmdT55xxReadBlock(const char *Cmd) {
}
printT5xxHeader(page1);
return T55xxReadBlock(block, page1, usepwd, override, password);
return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode);
}
bool DecodeT55xxBlock(){
@ -459,12 +476,32 @@ bool DecodeT5555TraceBlock() {
return (bool) ASKDemod("64 0 1", false, false, 1);
}
void T55xx_Print_DownlinkMode (uint8_t downlink_mode)
{
char Msg[80];
sprintf (Msg,"Downlink Mode used : ");
switch (downlink_mode) {
case 0 : strcat (Msg,"default/fixed bit length"); break;
case 1 : strcat (Msg,"long leading reference (r 1)"); break;
case 2 : strcat (Msg,"leading zero reference (r 2)"); break;
case 3 : strcat (Msg,"1 of 4 coding reference (r 3)"); break;
default :
strcat (Msg,"default/fixed bit length"); break;
}
PrintAndLog (Msg);
}
int CmdT55xxDetect(const char *Cmd){
bool errors = false;
bool useGB = false;
bool usepwd = false;
uint32_t password = 0;
uint8_t cmdp = 0;
uint8_t downlink_mode = 0;
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch(param_getchar(Cmd, cmdp)) {
@ -482,6 +519,12 @@ int CmdT55xxDetect(const char *Cmd){
useGB = true;
cmdp++;
break;
case 'r':
case 'R':
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
if (downlink_mode > 3) downlink_mode = 0;
cmdp +=2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -491,13 +534,16 @@ int CmdT55xxDetect(const char *Cmd){
if (errors) return usage_t55xx_detect();
if ( !useGB) {
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) )
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) )
return 0;
}
if ( !tryDetectModulation() )
PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'");
else {
// Add downlink mode for reference.
T55xx_Print_DownlinkMode (downlink_mode);
}
return 1;
}
@ -649,6 +695,7 @@ bool tryDetectModulation(){
config.block0 = tests[0].block0;
config.Q5 = tests[0].Q5;
config.ST = tests[0].ST;
printConfiguration( config);
return true;
}
@ -898,6 +945,8 @@ int CmdT55xxWriteBlock(const char *Cmd) {
uint8_t block = 0xFF; //default to invalid block
uint32_t data = 0; //default to blank Block
uint32_t password = 0; //default to blank Block 7
uint32_t downlink_mode = 0;
bool usepwd = false;
bool page1 = false;
bool gotdata = false;
@ -935,6 +984,12 @@ int CmdT55xxWriteBlock(const char *Cmd) {
page1 = true;
cmdp++;
break;
case 'r':
case 'R':
downlink_mode = param_getchar(Cmd, cmdp+1) - '0';
if (downlink_mode > 3) downlink_mode = 0;
cmdp +=2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -952,6 +1007,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
UsbCommand resp;
c.d.asBytes[0] = (page1) ? 0x2 : 0;
c.d.asBytes[0] |= (testMode) ? 0x4 : 0;
c.d.asBytes[0] |= (downlink_mode << 3);
char pwdStr[16] = {0};
snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password);
@ -963,6 +1019,7 @@ int CmdT55xxWriteBlock(const char *Cmd) {
c.arg[2] = password;
c.d.asBytes[0] |= 0x1;
}
clearCommandBuffer();
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){
@ -980,7 +1037,7 @@ int CmdT55xxReadTrace(const char *Cmd) {
return usage_t55xx_trace();
if (strlen(Cmd)==0)
if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) )
if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) )
return 0;
if ( config.Q5 ) {
@ -1070,7 +1127,7 @@ void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ){
PrintAndLog("-- T55x7 Trace Information ----------------------------------");
PrintAndLog("-------------------------------------------------------------");
PrintAndLog(" ACL Allocation class (ISO/IEC 15963-1) : 0x%02X (%d)", data.acl, data.acl);
PrintAndLog(" MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getTagInfo(data.mfc));
PrintAndLog(" MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getManufacturerName(data.mfc));
PrintAndLog(" CID : 0x%02X (%d) - %s", data.cid, data.cid, GetModelStrFromCID(data.cid));
PrintAndLog(" ICR IC Revision : %d", data.icr );
PrintAndLog(" Manufactured");
@ -1144,7 +1201,7 @@ int CmdT55xxInfo(const char *Cmd){
return usage_t55xx_info();
if (strlen(Cmd)==0)
if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) )
if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) )
return 1;
if (!DecodeT55xxBlock()) return 1;
@ -1212,20 +1269,21 @@ int CmdT55xxDump(const char *Cmd){
printT5xxHeader(0);
for ( uint8_t i = 0; i <8; ++i)
T55xxReadBlock(i, 0, usepwd, override, password);
T55xxReadBlock(i, 0, usepwd, override, password,0);
printT5xxHeader(1);
for ( uint8_t i = 0; i<4; i++)
T55xxReadBlock(i, 1, usepwd, override, password);
T55xxReadBlock(i, 1, usepwd, override, password,0);
return 1;
}
int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){
int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){
// arg0 bitmodes:
// bit0 = pwdmode
// bit1 = page to read from
uint8_t arg0 = (page<<1) | pwdmode;
arg0 |= (downlink_mode << 3);
UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}};
clearCommandBuffer();
@ -1403,9 +1461,23 @@ int CmdT55xxBruteForce(const char *Cmd) {
uint32_t start_password = 0x00000000; //start password
uint32_t end_password = 0xFFFFFFFF; //end password
bool found = false;
uint8_t downlink_mode = 0;
bool try_all_dl_modes = false;
uint8_t dl_mode = 0;
uint8_t cmd_offset = 0;
int cmd_opt = 0;
char cmdp = param_getchar(Cmd, 0);
if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce();
if (cmdp == 'r' || cmdp == 'R') {
downlink_mode = param_getchar(Cmd, 1) - '0'; // get 2nd option, as this is fixed order.
if (downlink_mode == 4) try_all_dl_modes = true;
if (downlink_mode > 3) downlink_mode = 0;
cmd_opt += 2; // To help start/end passwords for range to be found
cmd_offset += 4; // r <sp> x <sp> To help the string offset for filename start position in cmd
cmdp = param_getchar(Cmd, 2); // get 3rd option, as this is fixed order.
}
keyBlock = calloc(stKeyBlock, 6);
if (keyBlock == NULL) return 1;
@ -1414,7 +1486,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
int len = strlen(Cmd+2);
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
memcpy(filename, Cmd+2, len);
memcpy(filename, Cmd+2+cmd_offset, len);
FILE * f = fopen( filename , "r");
@ -1480,8 +1552,11 @@ int CmdT55xxBruteForce(const char *Cmd) {
PrintAndLog("Testing %08X", testpwd);
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) {
PrintAndLog("Aquireing data from device failed. Quitting");
// Try each downlink_mode if asked to
// donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){
if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) {
PrintAndLog("Acquiring data from device failed. Quitting");
free(keyBlock);
return 0;
}
@ -1491,8 +1566,14 @@ int CmdT55xxBruteForce(const char *Cmd) {
if ( found ) {
PrintAndLog("Found valid password: [%08X]", testpwd);
free(keyBlock);
T55xx_Print_DownlinkMode (dl_mode);
return 0;
}
if (!try_all_dl_modes) // Exit loop if not trying all downlink modes
dl_mode = 4;
}
}
PrintAndLog("Password NOT found.");
free(keyBlock);
@ -1502,8 +1583,8 @@ int CmdT55xxBruteForce(const char *Cmd) {
// Try to read Block 7, first :)
// incremental pwd range search
start_password = param_get32ex(Cmd, 0, 0, 16);
end_password = param_get32ex(Cmd, 1, 0, 16);
start_password = param_get32ex(Cmd, cmd_opt , 0, 16);
end_password = param_get32ex(Cmd, cmd_opt+1 , 0, 16);
if ( start_password >= end_password ) {
free(keyBlock);
@ -1524,29 +1605,36 @@ int CmdT55xxBruteForce(const char *Cmd) {
free(keyBlock);
return 0;
}
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) {
PrintAndLog("Aquireing data from device failed. Quitting");
// Try each downlink_mode if asked to
// donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3
for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){
if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) {
PrintAndLog("Acquiring data from device failed. Quitting");
free(keyBlock);
return 0;
}
found = tryDetectModulation();
if (found) break;
if (!try_all_dl_modes) // Exit loop if not trying all downlink modes
dl_mode = 4;
}
if (found) break;
i++;
}
PrintAndLog("");
if (found)
if (found){
PrintAndLog("Found valid password: [%08x]", i);
else
T55xx_Print_DownlinkMode (downlink_mode);
}
else{
PrintAndLog("");
PrintAndLog("Password NOT found. Last tried: [%08x]", --i);
}
free(keyBlock);
return 0;
}
// note length of data returned is different for different chips.
// some return all page 1 (64 bits) and others return just that block (32 bits)
// unfortunately the 64 bits makes this more likely to get a false positive...
@ -1558,7 +1646,7 @@ bool tryDetectP1(bool getData) {
bool st = true;
if ( getData ) {
if ( !AquireData(T55x7_PAGE1, 1, false, 0) )
if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) )
return false;
}
@ -1687,7 +1775,7 @@ int CmdT55xxDetectPage1(const char *Cmd){
if (errors) return usage_t55xx_detectP1();
if ( !useGB ) {
if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) )
if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) )
return false;
}
bool success = tryDetectP1(false);

View file

@ -98,7 +98,7 @@ bool tryDetectModulation(void);
extern bool tryDetectP1(bool getData);
bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5);
int special(const char *Cmd);
int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password );
int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode );
void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat );
void printT5555Trace( t5555_tracedata_t data, uint8_t repeat );

View file

@ -26,6 +26,7 @@
#include "util.h"
#include "util_posix.h"
#include "cmdscript.h"
#include "emv/cmdemv.h" // EMV
#ifdef WITH_SMARTCARD
#include "cmdsmartcard.h"
#endif
@ -42,7 +43,10 @@ static command_t CommandTable[] =
{"hw", CmdHW, 1, "{ Hardware commands... }"},
{"lf", CmdLF, 1, "{ Low Frequency commands... }"},
#ifdef WITH_SMARTCARD
{"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"},
{"sc", CmdSmartcard,1,"{ Smartcard commands... }"},
#else
{"emv", CmdEMV, 1, "{ EMV iso14443 }"},
#endif
{"script",CmdScript,1, "{ Scripting commands }"},
{"quit", CmdQuit, 1, "Exit program"},

File diff suppressed because it is too large Load diff

View file

@ -11,29 +11,12 @@
#ifndef CMDSMARTCARD_H__
#define CMDSMARTCARD_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "proxmark3.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
#include "util.h"
#include "loclass/fileutils.h" // saveFile
#include "cmdmain.h" // getfromdevice
#include "emv/emvcore.h" // decodeTVL
#include "emv/apduinfo.h" // APDUcode description
#include <stdint.h>
#include <stdbool.h>
#include "smartcard.h"
extern int CmdSmartcard(const char *Cmd);
extern bool smart_getATR(smart_card_atr_t *card);
extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
extern int CmdSmartRaw(const char* cmd);
extern int CmdSmartUpgrade(const char* cmd);
extern int CmdSmartInfo(const char* cmd);
extern int CmdSmartReader(const char *Cmd);
extern int usage_sm_raw(void);
extern int usage_sm_reader(void);
extern int usage_sm_info(void);
extern int usage_sm_upgrade(void);
#endif

View file

@ -9,12 +9,18 @@
// Code for communicating with the proxmark3 hardware.
//-----------------------------------------------------------------------------
#define _POSIX_C_SOURCE 199309L // need clock_gettime()
#include "comms.h"
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <pthread.h>
#if defined(__linux__) && !defined(NO_UNLINK)
#include <unistd.h> // for unlink()
#endif
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include "uart.h"
#include "ui.h"
#include "common.h"
@ -31,7 +37,6 @@ static bool offline;
typedef struct {
bool run; // If TRUE, continue running the uart_communication thread
bool block_after_ACK; // if true, block after receiving an ACK package
} communication_arg_t;
static communication_arg_t conn;
@ -45,6 +50,9 @@ static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER;
// Used by UsbReceiveCommand as a ring buffer for messages that are yet to be
// processed by a command handler (WaitForResponse{,Timeout})
#define CMD_BUFFER_SIZE 50
#define CMD_BUFFER_CHECK_TIME 10 // maximum time (in ms) to wait in getCommand()
static UsbCommand rxBuffer[CMD_BUFFER_SIZE];
// Points to the next empty position to write to
@ -55,6 +63,7 @@ static int cmd_tail = 0;
// to lock rxBuffer operations from different threads
static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t rxBufferSig = PTHREAD_COND_INITIALIZER;
// These wrappers are required because it is not possible to access a static
// global variable outside of the context of a single file.
@ -69,7 +78,7 @@ bool IsOffline() {
void SendCommand(UsbCommand *c) {
#ifdef COMMS_DEBUG
printf("Sending %04x cmd\n", c->cmd);
printf("Sending %04" PRIx64 " cmd\n", c->cmd);
#endif
if (offline) {
@ -101,8 +110,7 @@ void SendCommand(UsbCommand *c) {
* A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which
* operation. Right now we'll just have to live with this.
*/
void clearCommandBuffer()
{
void clearCommandBuffer() {
//This is a very simple operation
pthread_mutex_lock(&rxBufferMutex);
cmd_tail = cmd_head;
@ -113,11 +121,9 @@ void clearCommandBuffer()
* @brief storeCommand stores a USB command in a circular buffer
* @param UC
*/
static void storeCommand(UsbCommand *command)
{
static void storeCommand(UsbCommand *command) {
pthread_mutex_lock(&rxBufferMutex);
if( (cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail)
{
if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) {
// If these two are equal, we're about to overwrite in the
// circular buffer.
PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!");
@ -128,6 +134,7 @@ static void storeCommand(UsbCommand *command)
memcpy(destination, command, sizeof(UsbCommand));
cmd_head = (cmd_head + 1) % CMD_BUFFER_SIZE; //increment head and wrap
pthread_cond_signal(&rxBufferSig); // tell main thread that a new command can be retreived
pthread_mutex_unlock(&rxBufferMutex);
}
@ -135,13 +142,24 @@ static void storeCommand(UsbCommand *command)
/**
* @brief getCommand gets a command from an internal circular buffer.
* @param response location to write command
* @return 1 if response was returned, 0 if nothing has been received
* @return 1 if response was returned, 0 if nothing has been received in time
*/
static int getCommand(UsbCommand* response)
{
static int getCommand(UsbCommand* response, uint32_t ms_timeout) {
struct timespec end_time;
clock_gettime(CLOCK_REALTIME, &end_time);
end_time.tv_sec += ms_timeout / 1000;
end_time.tv_nsec += (ms_timeout % 1000) * 1000000;
if (end_time.tv_nsec > 1000000000) {
end_time.tv_nsec -= 1000000000;
end_time.tv_sec += 1;
}
pthread_mutex_lock(&rxBufferMutex);
//If head == tail, there's nothing to read, or if we just got initialized
if (cmd_head == cmd_tail){
int res = 0;
while (cmd_head == cmd_tail && !res) {
res = pthread_cond_timedwait(&rxBufferSig, &rxBufferMutex, &end_time);
}
if (res) { // timeout
pthread_mutex_unlock(&rxBufferMutex);
return 0;
}
@ -161,8 +179,7 @@ static int getCommand(UsbCommand* response)
// Entry point into our code: called whenever we received a packet over USB.
// Handle debug commands directly, store all other commands in circular buffer.
//----------------------------------------------------------------------------------
static void UsbCommandReceived(UsbCommand *UC)
{
static void UsbCommandReceived(UsbCommand *UC) {
switch (UC->cmd) {
// First check if we are handling a debug message
case CMD_DEBUG_PRINT_STRING: {
@ -187,6 +204,24 @@ static void UsbCommandReceived(UsbCommand *UC)
}
static bool receive_from_serial(serial_port sp, uint8_t *rx_buf, size_t len, size_t *received_len) {
size_t bytes_read = 0;
*received_len = 0;
// we eventually need to call uart_receive several times because it may timeout in the middle of a transfer
while (uart_receive(sp, rx_buf + *received_len, len - *received_len, &bytes_read) && bytes_read && *received_len < len) {
#ifdef COMMS_DEBUG
if (bytes_read != len - *received_len) {
printf("uart_receive() returned true but not enough bytes could be received. received: %zd, wanted to receive: %zd, already received before: %zd\n",
bytes_read, len - *received_len, *received_len);
}
#endif
*received_len += bytes_read;
bytes_read = 0;
}
return (*received_len == len);
}
static void
#ifdef __has_attribute
#if __has_attribute(force_align_arg_pointer)
@ -195,49 +230,70 @@ __attribute__((force_align_arg_pointer))
#endif
*uart_communication(void *targ) {
communication_arg_t *conn = (communication_arg_t*)targ;
size_t rxlen;
UsbCommand rx;
UsbCommand *prx = &rx;
uint8_t rx[sizeof(UsbCommand)];
size_t rxlen = 0;
uint8_t *prx = rx;
UsbCommand *command = (UsbCommand*)rx;
UsbResponse *response = (UsbResponse*)rx;
#if defined(__MACH__) && defined(__APPLE__)
disableAppNap("Proxmark3 polling UART");
#endif
while (conn->run) {
rxlen = 0;
bool ACK_received = false;
if (uart_receive(sp, (uint8_t *)prx, sizeof(UsbCommand) - (prx-&rx), &rxlen) && rxlen) {
prx = rx;
size_t bytes_to_read = offsetof(UsbResponse, d); // the fixed part of a new style UsbResponse. Otherwise this will be cmd and arg[0] (64 bit each)
if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
prx += rxlen;
if (prx-&rx < sizeof(UsbCommand)) {
continue;
}
UsbCommandReceived(&rx);
if (rx.cmd == CMD_ACK) {
if (response->cmd & CMD_VARIABLE_SIZE_FLAG) { // new style response with variable size
#ifdef COMMS_DEBUG
PrintAndLog("received new style response %04" PRIx16 ", datalen = %zd, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32,
response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]);
#endif
bytes_to_read = response->datalen;
if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
UsbCommand resp;
resp.cmd = response->cmd & ~CMD_VARIABLE_SIZE_FLAG; // remove the flag
resp.arg[0] = response->arg[0];
resp.arg[1] = response->arg[1];
resp.arg[2] = response->arg[2];
memcpy(&resp.d.asBytes, &response->d.asBytes, response->datalen);
UsbCommandReceived(&resp);
if (resp.cmd == CMD_ACK) {
ACK_received = true;
}
}
prx = &rx;
} else { // old style response uses same data structure as commands. Fixed size.
#ifdef COMMS_DEBUG
PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64, command->cmd, command->arg[0]);
#endif
bytes_to_read = sizeof(UsbCommand) - bytes_to_read;
if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
UsbCommandReceived(command);
if (command->cmd == CMD_ACK) {
ACK_received = true;
}
}
}
}
pthread_mutex_lock(&txBufferMutex);
if (conn->block_after_ACK) {
// if we just received an ACK, wait here until a new command is to be transmitted
// if we received an ACK the PM has done its job and waits for another command.
// We therefore can wait here as well until a new command is to be transmitted.
// The advantage is that the next command will be transmitted immediately without the need to wait for a receive timeout
if (ACK_received) {
while (!txBuffer_pending) {
pthread_cond_wait(&txBufferSig, &txBufferMutex);
}
}
}
if (txBuffer_pending) {
if (!uart_send(sp, (uint8_t*) &txBuffer, sizeof(UsbCommand))) {
PrintAndLog("Sending bytes to proxmark failed");
}
txBuffer_pending = false;
pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty
}
pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty
pthread_mutex_unlock(&txBufferMutex);
}
@ -262,13 +318,13 @@ __attribute__((force_align_arg_pointer))
* @param show_warning display message after 2 seconds
* @return true if command was returned, otherwise false
*/
bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning)
{
UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
SendCommand(&c);
bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) {
uint64_t start_time = msclock();
UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
SendCommand(&c);
UsbCommand resp;
if (response == NULL) {
response = &resp;
@ -276,7 +332,16 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon
int bytes_completed = 0;
while (true) {
if (getCommand(response)) {
if (msclock() - start_time > ms_timeout) {
break; // timeout
}
if (msclock() - start_time > 2000 && show_warning) {
// 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
PrintAndLog("Waiting for a response from the proxmark...");
PrintAndLog("You can cancel this operation by pressing the pm3 button");
show_warning = false;
}
if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]);
memcpy(dest + response->arg[0], response->d.asBytes, copy_bytes);
@ -285,23 +350,45 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon
return true;
}
}
if (msclock() - start_time > ms_timeout) {
break;
}
return false;
}
bool GetFromFpgaRAM(uint8_t *dest, int bytes) {
uint64_t start_time = msclock();
UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}};
SendCommand(&c);
UsbCommand response;
int bytes_completed = 0;
bool show_warning = true;
while (true) {
if (msclock() - start_time > 2000 && show_warning) {
PrintAndLog("Waiting for a response from the proxmark...");
PrintAndLog("You can cancel this operation by pressing the pm3 button");
show_warning = false;
}
if (getCommand(&response, CMD_BUFFER_CHECK_TIME)) {
if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]);
memcpy(dest + response.arg[0], response.d.asBytes, copy_bytes);
bytes_completed += copy_bytes;
} else if (response.cmd == CMD_ACK) {
return true;
}
}
}
return false;
}
bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) {
bool OpenProxmark(void *port, bool wait_for_port, int timeout) {
char *portname = (char *)port;
if (!wait_for_port) {
sp = uart_open(portname);
@ -333,7 +420,6 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode)
// start the USB communication thread
serial_port_name = portname;
conn.run = true;
conn.block_after_ACK = flash_mode;
pthread_create(&USB_communication_thread, NULL, &uart_communication, &conn);
return true;
}
@ -361,15 +447,6 @@ void CloseProxmark(void) {
uart_close(sp);
}
#if defined(__linux__) && !defined(NO_UNLINK)
// Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/*
//
// This may be disabled at compile-time with -DNO_UNLINK (used for a JNI-based serial port on Android).
if (serial_port_name) {
unlink(serial_port_name);
}
#endif
// Clean up our state
sp = NULL;
serial_port_name = NULL;
@ -397,30 +474,28 @@ bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeo
printf("Waiting for %04x cmd\n", cmd);
#endif
uint64_t start_time = msclock();
if (response == NULL) {
response = &resp;
}
uint64_t start_time = msclock();
// Wait until the command is received
while (true) {
while(getCommand(response)) {
if (cmd == CMD_UNKNOWN || response->cmd == cmd) {
return true;
if (ms_timeout != -1 && msclock() > start_time + ms_timeout) {
break; // timeout
}
}
if (msclock() - start_time > ms_timeout) {
break;
}
if (msclock() - start_time > 2000 && show_warning) {
// 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
PrintAndLog("Waiting for a response from the proxmark...");
PrintAndLog("You can cancel this operation by pressing the pm3 button");
show_warning = false;
}
if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
if (cmd == CMD_UNKNOWN || response->cmd == cmd) {
return true;
}
}
}
return false;
}

View file

@ -9,31 +9,24 @@
// Code for communicating with the proxmark3 hardware.
//-----------------------------------------------------------------------------
#ifndef COMMS_H_
#define COMMS_H_
#ifndef COMMS_H__
#define COMMS_H__
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include "usb_cmd.h"
#include "uart.h"
#ifndef CMD_BUFFER_SIZE
#define CMD_BUFFER_SIZE 50
#endif
extern void SetOffline(bool new_offline);
extern bool IsOffline();
extern bool OpenProxmark(void *port, bool wait_for_port, int timeout);
extern void CloseProxmark(void);
extern void SendCommand(UsbCommand *c);
extern void clearCommandBuffer();
extern bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning);
extern bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout);
extern bool WaitForResponse(uint32_t cmd, UsbCommand* response);
extern bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning);
extern bool GetFromFpgaRAM(uint8_t *dest, int bytes);
void SetOffline(bool new_offline);
bool IsOffline();
bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode);
void CloseProxmark(void);
void SendCommand(UsbCommand *c);
void clearCommandBuffer();
bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning);
bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout);
bool WaitForResponse(uint32_t cmd, UsbCommand* response);
bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning);
#endif // COMMS_H_
#endif // COMMS_H__

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