Merge branch 'master' into smartcard-relay

This commit is contained in:
Grayson Martin 2023-11-11 13:05:11 -06:00
commit 4e346e8ca2
No known key found for this signature in database
GPG key ID: 4914C62F2696A273
159 changed files with 10035 additions and 2880 deletions

View file

@ -70,7 +70,7 @@ jobs:
env: env:
V: 1 V: 1
PLATFORM_EXTRAS: BTADDON PLATFORM_EXTRAS: BTADDON
run: make run: make -j$((`nproc` + 1))
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2

View file

@ -50,14 +50,12 @@ jobs:
- name: Build - name: Build
env: env:
V: 1 V: 1
run: make run: make -j$((`sysctl -n hw.ncpu` + 1))
- name: Test - name: Test
run: make check run: make check
macos-make-btaddon: macos-make-btaddon:
if: always()
needs: [macos-make]
runs-on: macos-latest runs-on: macos-latest
steps: steps:
@ -93,14 +91,12 @@ jobs:
env: env:
V: 1 V: 1
PLATFORM_EXTRAS: BTADDON PLATFORM_EXTRAS: BTADDON
run: make run: make -j$((`sysctl -n hw.ncpu` + 1))
- name: Test - name: Test
run: make check run: make check
macos-cmake: macos-cmake:
if: always()
needs: [macos-make, macos-make-btaddon]
runs-on: macos-latest runs-on: macos-latest
steps: steps:
@ -144,7 +140,7 @@ jobs:
- name: Build - name: Build
env: env:
VERBOSE: 1 VERBOSE: 1
run: make run: make -j$((`sysctl -n hw.ncpu` + 1))
working-directory: client/build/ working-directory: client/build/
- name: Test - name: Test

View file

@ -41,14 +41,12 @@ jobs:
- name: Build - name: Build
env: env:
V: 1 V: 1
run: make run: make -j$((`nproc` + 1))
- name: Test - name: Test
run: make check run: make check
ubuntu-make-btaddon: ubuntu-make-btaddon:
if: always()
needs: [ubuntu-make]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -74,14 +72,12 @@ jobs:
env: env:
V: 1 V: 1
PLATFORM_EXTRAS: BTADDON PLATFORM_EXTRAS: BTADDON
run: make run: make -j$((`nproc` + 1))
- name: Test - name: Test
run: make check run: make check
ubuntu-cmake: ubuntu-cmake:
if: always()
needs: [ubuntu-make, ubuntu-make-btaddon]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -115,7 +111,7 @@ jobs:
- name: Build - name: Build
env: env:
VERBOSE: 1 VERBOSE: 1
run: make run: make -j$((`nproc` + 1))
working-directory: client/build/ working-directory: client/build/
- name: Test - name: Test

View file

@ -54,7 +54,7 @@ jobs:
run: make clean run: make clean
- name: Build - name: Build
run: make V=1 run: make -j $([System.Environment]::ProcessorCount + 1) V=1
- name: Test - name: Test
run: make check run: make check
@ -63,7 +63,7 @@ jobs:
run: make clean run: make clean
- name: Build btaddon - name: Build btaddon
run: make V=1 PLATFORM_EXTRAS=BTADDON run: make -j $([System.Environment]::ProcessorCount + 1) V=1 PLATFORM_EXTRAS=BTADDON
- name: Test btaddon - name: Test btaddon
run: make check run: make check
@ -84,7 +84,7 @@ jobs:
working-directory: client/build/ working-directory: client/build/
- name: Build cmake - name: Build cmake
run: make VERBOSE=1 run: make -j $([System.Environment]::ProcessorCount + 1) VERBOSE=1
working-directory: client/build/ working-directory: client/build/
- name: Test cmake - name: Test cmake
@ -141,7 +141,7 @@ jobs:
run: make clean run: make clean
- name: Build - name: Build
run: make V=1 run: make -j$((`nproc` + 1)) V=1
- name: Test - name: Test
run: make check run: make check
@ -150,7 +150,7 @@ jobs:
run: make clean run: make clean
- name: Build btaddon - name: Build btaddon
run: make V=1 PLATFORM_EXTRAS=BTADDON run: make -j$((`nproc` + 1)) V=1 PLATFORM_EXTRAS=BTADDON
- name: Test btaddon - name: Test btaddon
run: make check run: make check
@ -171,7 +171,7 @@ jobs:
working-directory: client/build/ working-directory: client/build/
- name: Build cmake - name: Build cmake
run: make VERBOSE=1 run: make -j$((`nproc` + 1)) VERBOSE=1
working-directory: client/build/ working-directory: client/build/
- name: Test cmake - name: Test cmake

View file

@ -1,11 +1,61 @@
# Change Log Change Log
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Use proxmark3 as a generic smartcard reader with other software with `smart relay` (@gm3197) - Use proxmark3 as a generic smartcard reader with other software with `smart relay` (@gm3197)
- Added `tools\mfkeys\staticnested` - program to recover static nested keys (@iceman1001)
- Added `pm3_gen_dictionary.py` - python script to extract and save all keys from MFC dump files. (@iceman1001)
- Changed `hf mfu info` - now detect MIFARE Ultralight AES (@iceman1001)
- Changed `hf mf autopwn` - now supports multiple user supplied keys (@iceman1001)
- Added `hf mf gchpwd` command for change Gen4 GTU card access password (@merlokk)
- Added `--ms` option in `hw status` to specify the timeout of connection speed test (@wh201906)
- Added `hf mf ginfo` command for get info about Gen4 GTU configuration (@merlokk)
- Added support for loading Flipper PICOPASS dump files (@iceman1001)
- Fixed unknown chip identification (@jmichelp)
- Fixed `nfc decode` - now properly handles MFU dump files (@iceman1001)
- Added support for loading Flipper MCT/MFU dump files (@iceman1001)
- Changed `data bmap` - now default `-m` is 8 (@iceman1001)
- Added support for NTAG424 cards. (@dankar)
- Additional fixes to configcard code for keyroll mode based on nfc-iclass output (@Antiklesys)
- Changed lf sampling - improved the performance (@yah01)
- Added `bind` option for network connections to specify the outbound address and port (@wh201906)
- Changed `lf em 4x05 dump` - now supports the `--ns` nosave parameter (@iceman1001)
- Fixed some wrong synchronization waits in usb_write() to increase the communication speed (@wh201906)
- Added new command `data bmap` - breaks down a hexvalue to a binary template (@iceman1001)
- Changed aid_desfire.json - added entreis from the Metrodroid project (@iceman1001)
- Changed mad.json - added entries from the Metrodroid project (@iceman1001)
- Changed `hf iclass dump` - now allow no save of dumped data (@iceman1001)
- Changed `hf iclass calcnewkey` - Added calculations for old key elite and new key non elite (@Antiklesys)
- Changed the CLI prompt to show tcp/udp if used (@iceman1001)
- Changed `hw ping` - now shows transfer time (@doegox)
- Added `hf mf encodehid` - writes HID legacy credential to a empty MFC (@iceman1001)
- Added `hf iclass sam` - Added support for HID SAM Picopass communications (@iceman1001)
- Add support for quoted arguments in the CLI, allowing spaces in them which
are removed automatically (@jmichelp)
- Added UDP support on Windows (@wh201906)
- Added client communication timeout to preferences (@iceman1001)
- Added IPv6 support (@wh201906)
- Fixed `lf hid clone --bin` - now correctly handles sentinel bits (@iceman1001)
- Experimental UDP support in linux (@iceman1001, @wh201906)
- Changed CI scripts to speed up the builds (@wh201906)
- Changed the timeout of local TCP connections (@wh201906)
- Finalized implementation of configcard generation for keyroll when cardhelper is not present (@Antiklesys)
- Added documentation for compiling on iOS (@The-SamminAter)
- Fixed `hf iclass wrbl` - pagemap bit map for secured is now handled better (@iceman1001)
- Changed `hf iclass view/decrypt` to detect SIO lengths better and show if legacy credentials are encrypted (@nvx)
- Changed the json file formats for mfc, 14b, 15, legic, cryptorf, ndef (@iceman1001)
- Deprecated the EML file format when saving dump files. (@iceman1001)
- Added `sim014.bin` - new sim module firmware v4.42 with improved ISO7816 Protocol T0 support (@gentilkiwi)
- Added datasheet for sim module (@iceman1001)
- Changed `smart raw --timeout` - allows for a custom timeout (@iceman1001)
- Changed `lf t55 detectp1` - now also accepts 0xE039 Silicon Craft Tech as valid card (@iceman1001)
- Fixed `utils.lua` library function "convertdectohex" wasn't working (@iceman1001) - Fixed `utils.lua` library function "convertdectohex" wasn't working (@iceman1001)
- Added `hf iclass creditepurse` command to allow crediting the epurse debit value (@nvx) - Added `hf iclass creditepurse` command to allow crediting the epurse debit value (@nvx)
- Modified `hf iclass configcard` to only support online mode (@Antiklesys)
- Modified `hf iclass configcard` command to generate config cards without a cardhelper module by porting the contents of blocks 6 & 7 from nfc-iclass (@Antiklesys)
- Fixed `hf iclass info` command showing incorrectly in offline mode (@Antiklesys)
- The "doc/magic_cards_notes.md" file has been rebuilt, filled up, and so on. (@team-orangeBlue)
## [Raccoon.4.17140][2023-09-09] ## [Raccoon.4.17140][2023-09-09]
- Changed text and adjust pm3_test case for mf_aes_brute (@doegox) - Changed text and adjust pm3_test case for mf_aes_brute (@doegox)
@ -59,7 +109,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed compiling liblua on iOS (@The-SamminAter) - Fixed compiling liblua on iOS (@The-SamminAter)
- Changed `hf_mf_luxeo_dump.lua` - now have list of keys to iterate (@iceman1001) - Changed `hf_mf_luxeo_dump.lua` - now have list of keys to iterate (@iceman1001)
- Fixed the timeout of TCP connections (@wh201906) - Fixed the timeout of TCP connections (@wh201906)
- Changed the connection timeout configurable (@wh201906) - Added `hw timeout` - make the connection timeout configurable (@wh201906)
## [Seven.4.16717][2023-06-25] ## [Seven.4.16717][2023-06-25]
- Change `hf 14a info` - now identifes QL88 tags (@iceman1001) - Change `hf 14a info` - now identifes QL88 tags (@iceman1001)
@ -299,6 +349,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added new standalone mode `lf_em4100rsww` (@zabszk) - Added new standalone mode `lf_em4100rsww` (@zabszk)
- Fixed `hf 15 slixdisable` wrong pass id (@r1ddl3rz) - Fixed `hf 15 slixdisable` wrong pass id (@r1ddl3rz)
- Added `script run hf_mf_hid_sim.lua` (@micsen) - Added `script run hf_mf_hid_sim.lua` (@micsen)
- Added flashmem support in `HF_14BSNIFF` standalone mode (@wh201906)
- Changed `HF_14ASNIFF` standalone mode - now supports Proxmark3 without flashmem (@wh201906)
## [Frostbit.4.14831][2022-01-11] ## [Frostbit.4.14831][2022-01-11]
- Changed Wiegand format lookup - now case-insensitive (@iceman1001) - Changed Wiegand format lookup - now case-insensitive (@iceman1001)

View file

@ -34,7 +34,7 @@ all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfk
#all clean install uninstall check: %: hitag2crack/% #all clean install uninstall check: %: hitag2crack/%
INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py pm3_amii_bin2eml.pl pm3_reblay-emulating.py pm3_reblay-reading.py INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py pm3_amii_bin2eml.pl pm3_reblay-emulating.py pm3_reblay-reading.py
INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt sim014.bin sim014.sha512.txt
INSTALLSCRIPTS=pm3 pm3-flash pm3-flash-all pm3-flash-bootrom pm3-flash-fullimage INSTALLSCRIPTS=pm3 pm3-flash pm3-flash-all pm3-flash-bootrom pm3-flash-fullimage
INSTALLSHARES=tools/jtag_openocd traces INSTALLSHARES=tools/jtag_openocd traces
INSTALLDOCS=doc/*.md doc/md INSTALLDOCS=doc/*.md doc/md

View file

@ -10,8 +10,7 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the
| Actions OSX CI | Actions Ubuntu CI | Actions Windows CI | | Actions OSX CI | Actions Ubuntu CI | Actions Windows CI |
|:--------------:|:------------------:|:------------------:| |:--------------:|:------------------:|:------------------:|
| ![MacOS Build and Test](https://github.com/RfidResearchGroup/proxmark3/workflows/MacOS%20Build%20and%20Test/badge.svg?branch=master) | ![Ubuntu Build and Test](https://github.com/RfidResearchGroup/proxmark3/workflows/Ubuntu%20Build%20and%20Test/badge.svg?branch=master) | [![Windows Build and Test](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml) | | [![MacOS Build and Test](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/macos.yml/badge.svg?branch=master)](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/macos.yml) | [![Ubuntu Build and Test](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/ubuntu.yml/badge.svg?branch=master)](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/ubuntu.yml) | [![Windows Build and Test](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml) |
# Table of Contents # Table of Contents
1. [PROXMARK3 INSTALLATION AND OVERVIEW](#proxmark3-installation-and-overview) 1. [PROXMARK3 INSTALLATION AND OVERVIEW](#proxmark3-installation-and-overview)
@ -40,6 +39,7 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the
| [macOS - Setup and Build](/doc/md/Installation_Instructions/macOS-Compile-From-Source-Instructions.md) || | [macOS - Setup and Build](/doc/md/Installation_Instructions/macOS-Compile-From-Source-Instructions.md) ||
| [Windows - Setup and Build](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md) || | [Windows - Setup and Build](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md) ||
| [Termux / Android - Setup and Build](/doc/termux_notes.md) || | [Termux / Android - Setup and Build](/doc/termux_notes.md) ||
| [iOS - Setup and Build](/doc/md/Installation_Instructions/iOS-Installation-Instructions.md)
| [Blue Shark Manual](/doc/bt_manual_v10.md) | [Command Cheat Sheet](/doc/cheatsheet.md)| | [Blue Shark Manual](/doc/bt_manual_v10.md) | [Command Cheat Sheet](/doc/cheatsheet.md)|
| [Advanced Compilation Parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md) | [More Cheat Sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)| | [Advanced Compilation Parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md) | [More Cheat Sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
| [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) | [Complete Client Command Set](/doc/commands.md) | | [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) | [Complete Client Command Set](/doc/commands.md) |
@ -77,6 +77,7 @@ We define generic Proxmark3 platforms as following devices.
- Ryscorp green PCB version - Ryscorp green PCB version
- Radiowar black PCB version - Radiowar black PCB version
- numerous Chinese adapted versions of the RDV3 easy (kkmoon, PiSwords etc) - numerous Chinese adapted versions of the RDV3 easy (kkmoon, PiSwords etc)
- Proxmark3 SE (Second edition) (BLE enabled)
**Not supported** **Not supported**
- ⚠ Proxmark Evolution (EVO) - ⚠ Proxmark Evolution (EVO)
@ -96,8 +97,6 @@ We define generic Proxmark3 platforms as following devices.
- **Note**: unknown device hw - **Note**: unknown device hw
- ⚠ Proxmark3 Ultimate - ⚠ Proxmark3 Ultimate
- **Note**: unknown device hw - **Note**: unknown device hw
- ⚠ Proxmark3 SE
- **Note**: unknown device hw
When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work. When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work.
@ -185,6 +184,7 @@ This repo compiles nicely on
- Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian - Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian
- Android / Termux - Android / Termux
- macOS / Homebrew (or MacPorts, experimental) / Apple Silicon M1 - macOS / Homebrew (or MacPorts, experimental) / Apple Silicon M1
- iOS (Jailbroken, rootful)
- Docker container - Docker container
- [ Iceman repo based ubuntu 18.04 container ](https://hub.docker.com/r/secopsconsult/proxmark3) - [ Iceman repo based ubuntu 18.04 container ](https://hub.docker.com/r/secopsconsult/proxmark3)
- [ Iceman fork based container v1.7 ](https://hub.docker.com/r/iceman1001/proxmark3/) - [ Iceman fork based container v1.7 ](https://hub.docker.com/r/iceman1001/proxmark3/)

View file

@ -37,13 +37,13 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
SRC_HF = hfops.c SRC_HF = hfops.c
SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_mfc.c sam_seos.c
#UNUSED: mifaresniff.c #UNUSED: mifaresniff.c
SRC_ISO14443b = iso14443b.c SRC_ISO14443b = iso14443b.c
SRC_FELICA = felica.c SRC_FELICA = felica.c
SRC_CRAPTO1 = crypto1.c des.c desfire_crypto.c mifaredesfire.c aes.c platform_util.c SRC_CRAPTO1 = crypto1.c des.c desfire_crypto.c mifaredesfire.c aes.c platform_util.c
SRC_CRC = crc.c crc16.c crc32.c SRC_CRC = crc.c crc16.c crc32.c
SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c sam_picopass.c
SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c
SRC_NFCBARCODE = thinfilm.c SRC_NFCBARCODE = thinfilm.c

View file

@ -69,7 +69,6 @@
#define HF_ICALSSS_READSIM_TEMP_MOD_BIN "iceclass-temp-mod.bin" #define HF_ICALSSS_READSIM_TEMP_MOD_BIN "iceclass-temp-mod.bin"
#define HF_ICLASS_FULLSIM_MOD "iceclass-modified" #define HF_ICLASS_FULLSIM_MOD "iceclass-modified"
#define HF_ICLASS_FULLSIM_MOD_BIN HF_ICLASS_FULLSIM_MOD".bin" #define HF_ICLASS_FULLSIM_MOD_BIN HF_ICLASS_FULLSIM_MOD".bin"
#define HF_ICLASS_FULLSIM_MOD_EML HF_ICLASS_FULLSIM_MOD".eml"
#define HF_ICLASS_ATTACK_BIN "iclass_mac_attack" #define HF_ICLASS_ATTACK_BIN "iclass_mac_attack"
#define HF_ICLASS_CC_A "iceclass_cc_a.bin" #define HF_ICLASS_CC_A "iceclass_cc_a.bin"
@ -117,10 +116,6 @@ static bool have_aa2(void) {
return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8); return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
} }
static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
}
static uint8_t csns[8 * NUM_CSNS] = { static uint8_t csns[8 * NUM_CSNS] = {
0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,

View file

@ -28,9 +28,10 @@
#include "iso14443a.h" #include "iso14443a.h"
#include "protocols.h" #include "protocols.h"
#include "cmd.h" #include "cmd.h"
#include "commonutil.h"
void ModInfo(void) { void ModInfo(void) {
DbpString(" HF - Reading Visa cards & Emulating a Visa MSD Transaction(ISO14443) - (Salvador Mendoza)"); DbpString(" HF - Reading VISA cards & Emulating a VISA MSD Transaction(ISO14443) - (Salvador Mendoza)");
} }
/* This standalone implements two different modes: reading and emulating. /* This standalone implements two different modes: reading and emulating.
@ -132,9 +133,15 @@ static uint8_t treatPDOL(const uint8_t *apdu) {
void RunMod(void) { void RunMod(void) {
StandAloneMode(); StandAloneMode();
DbpString(_YELLOW_(">>") "Reading Visa cards & Emulating a Visa MSD Transaction a.k.a. MSDSal Started " _YELLOW_("<<")); DbpString("");
DbpString(_YELLOW_(">>>") " Reading VISA cards & Emulating a VISA MSD Transaction a.k.a. MSDSal Started " _YELLOW_("<<<"));
DbpString("");
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// free eventually allocated BigBuf memory but keep Emulator Memory
// also sets HIGH pointer of BigBuf enabling us to malloc w/o fiddling w the reserved emulator memory
BigBuf_free_keep_EM();
//For reading process //For reading process
iso14a_card_select_t card_a_info; iso14a_card_select_t card_a_info;
@ -146,10 +153,32 @@ void RunMod(void) {
0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44,
0x46, 0x30, 0x31, 0x00 0x46, 0x30, 0x31, 0x00
}; };
uint8_t visa[13] = {
0x00, 0xA4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, uint8_t visa[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00 };
0x00, 0x03, 0x10, 0x10, 0x00
/*
uint8_t select_aid_hdr[5] = { 0x00, 0xA4, 0x04, 0x00, 0x00 };
static const char* aid_list [] = {
"A00000000305076010", // VISA ELO Credit
"A0000000031010", // VISA Debit/Credit (Classic)
"A000000003101001", // VISA Credit
"A000000003101002", // VISA Debit
"A0000000032010", // VISA Electron
"A0000000032020", // VISA
"A0000000033010", // VISA Interlink
"A0000000034010", // VISA Specific
"A0000000035010", // VISA Specific
"A0000000036010", // Domestic Visa Cash Stored Value
"A0000000036020", // International Visa Cash Stored Value
"A0000000038002", // VISA Auth, VisaRemAuthen EMV-CAP (DPA)
"A0000000038010", // VISA Plus
"A0000000039010", // VISA Loyalty
"A000000003999910", // VISA Proprietary ATM
"A000000098", // Visa USA Debit Card
"A0000000980848", // Visa USA Debit Cardv
}; };
*/
uint8_t processing [8] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00}; uint8_t processing [8] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
uint8_t sfi[5] = {0x00, 0xb2, 0x01, 0x0c, 0x00}; uint8_t sfi[5] = {0x00, 0xb2, 0x01, 0x0c, 0x00};
@ -161,13 +190,17 @@ void RunMod(void) {
bool existpdol; bool existpdol;
// - MSD token card format - // - MSD token card format -
// //
//Card number: 4412 3456 0578 1234 // Card number.............. 4412 3456 0578 1234
//Expiration date: 17/11 // Expiration date.......... 17/11
//Service code: 201 // Service code............. 201
//Discretionary data: 0000030000991 // Discretionary data....... 0000030000991
// Pin verification value... 0000
// CVV / iCvv............... 030
// Trailing................. 000991
// 44 12 34 56 05 78 12 34 D 1711 2 01 00 00 03 00 00 99 1
// char token[19] = {0x44,0x12,0x34,0x56,0x05,0x78,0x12,0x34,0xd1,0x71,0x12,0x01,0x00,0x00,0x03,0x00,0x00,0x99,0x1f}; // char token[19] = {0x44,0x12,0x34,0x56,0x05,0x78,0x12,0x34,0xd1,0x71,0x12,0x01,0x00,0x00,0x03,0x00,0x00,0x99,0x1f};
// //
// It is possible to initialize directly the emulation mode, having "token" with data and set "chktoken" = true ;) // It is possible to initialize directly the emulation mode, having "token" with data and set "chktoken" = true ;)
@ -175,34 +208,31 @@ void RunMod(void) {
char token[19] = {0x00}; char token[19] = {0x00};
bool chktoken = false; bool chktoken = false;
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
// Such a response is less time critical, so we can prepare them on the fly
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
// UID 4 bytes(could be 7 bytes if needed it) // UID 4 bytes(could be 7 bytes if needed it)
uint8_t flags = FLAG_4B_UID_IN_DATA; uint8_t flags = FLAG_4B_UID_IN_DATA;
// in case there is a read command received we shouldn't break // in case there is a read command received we shouldn't break
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t visauid[7] = {0x01, 0x02, 0x03, 0x04}; uint8_t visauid[7] = {0xE9, 0x66, 0x5D, 0x20};
memcpy(data, visauid, 4); memcpy(data, visauid, 4);
// to initialize the emulation // to initialize the emulation
uint8_t tagType = 11; // 11 = ISO/IEC 14443-4 - javacard (JCOP)
tag_response_info_t *responses; tag_response_info_t *responses;
uint32_t cuid = 0; uint32_t cuid = 0;
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
uint8_t pages = 0;
// command buffers // command buffers
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 }; uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 }; uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
// Such a response is less time critical, so we can prepare them on the fly
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0}; uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0}; uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
// to know the transaction status // to know the transaction status
uint8_t prevCmd = 0; uint8_t prevCmd = 0;
@ -223,11 +253,11 @@ void RunMod(void) {
// Checking if the user wants to go directly to emulation mode using a hardcoded track 2 // Checking if the user wants to go directly to emulation mode using a hardcoded track 2
if (chktoken == true && token[0] != 0x00) { if (chktoken == true && token[0] != 0x00) {
state = STATE_EMU; state = STATE_EMU;
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]")); DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader..."); DbpString("Waiting for a card reader...");
} else { } else {
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]")); DbpString("Initialized [ " _YELLOW_("reading mode") " ]");
DbpString("\n"_YELLOW_("!!") "Waiting for a Visa card..."); DbpString("Waiting for a VISA card...");
} }
for (;;) { for (;;) {
@ -240,20 +270,20 @@ void RunMod(void) {
int button_pressed = BUTTON_HELD(1000); int button_pressed = BUTTON_HELD(1000);
if (button_pressed == BUTTON_HOLD) if (button_pressed == BUTTON_HOLD) {
break; break;
else if (button_pressed == BUTTON_SINGLE_CLICK) { } else if (button_pressed == BUTTON_SINGLE_CLICK) {
// pressing one time change between reading & emulation // pressing one time change between reading & emulation
if (state == STATE_READ) { if (state == STATE_READ) {
if (chktoken == true && token[0] != 0x00) { if (chktoken == true && token[0] != 0x00) {
// only change to emulation if it saved a track 2 in memory // only change to emulation if it saved a track 2 in memory
state = STATE_EMU; state = STATE_EMU;
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]")); DbpString("[ " _BLUE_("Emulation mode") " ]");
} else } else
DbpString(_YELLOW_("!!") "Nothing in memory to emulate"); DbpString(_YELLOW_("Nothing in memory to emulate"));
} else { } else {
state = STATE_READ; state = STATE_READ;
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]")); DbpString("[ " _YELLOW_("Reading mode") " ]");
} }
} }
@ -261,35 +291,40 @@ void RunMod(void) {
if (state == STATE_READ) { if (state == STATE_READ) {
LED_A_ON(); LED_A_ON();
if (chktoken) if (chktoken) {
LED_C_ON(); LED_C_ON();
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) { if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
DbpString(_YELLOW_("+") "Found ISO 14443 Type A!");
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
chktoken = false; chktoken = false;
LED_C_OFF(); LED_C_OFF();
LED_B_ON(); LED_B_ON();
// add loop visa
// for (int i = 0; i < ARRAYLEN(AIDlist); i ++) {
// hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu, &sam_len);
uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apduslen[i], false, apdubuffer, NULL); uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apduslen[i], false, apdubuffer, NULL);
if (apdulen > 0) { if (apdulen > 0) {
DbpString(_YELLOW_("[ ") "Proxmark command" _YELLOW_(" ]")); DbpString("[ " _YELLOW_("Proxmark command") " ]");
Dbhexdump(apduslen[i], apdus[i], false); Dbhexdump(apduslen[i], apdus[i], false);
DbpString(_GREEN_("[ ") "Card answer" _GREEN_(" ]")); DbpString("[ " _GREEN_("Card answer") " ]");
Dbhexdump(apdulen - 2, apdubuffer, false); Dbhexdump(apdulen - 2, apdubuffer, false);
DbpString("----"); DbpString("-------------------------------");
for (uint8_t u = 0; u < apdulen; u++) { for (uint8_t u = 0; u < apdulen; u++) {
if (i == 1) { if (i == 1) {
// check for PDOL // check for PDOL
if (apdubuffer[u] == 0x9F && apdubuffer[u + 1] == 0x38) { if (apdubuffer[u] == 0x9F && apdubuffer[u + 1] == 0x38) {
for (uint8_t e = 0; e <= apdubuffer[u + 2]; e++)
for (uint8_t e = 0; e <= apdubuffer[u + 2]; e++) {
pdol[e] = apdubuffer[u + e + 2]; pdol[e] = apdubuffer[u + e + 2];
}
// generate a challenge // generate a challenge
plen = treatPDOL(pdol); plen = treatPDOL(pdol);
@ -309,25 +344,27 @@ void RunMod(void) {
} }
if (i == 1) { if (i == 1) {
DbpString(_GREEN_("[ ") "Challenge generated" _GREEN_(" ]")); DbpString("[ "_GREEN_("Challenge generated") " ]");
Dbhexdump(plen, existpdol ? ppdol : processing, false); Dbhexdump(plen, existpdol ? ppdol : processing, false);
} }
} else { } else {
DbpString(_YELLOW_("!!") "Error reading the card"); DbpString(_RED_("Error reading the card"));
} }
LED_B_OFF(); LED_B_OFF();
} }
if (chktoken) { if (chktoken) {
DbpString(_RED_("[ ") "Track 2" _RED_(" ]")); DbpString("[ " _GREEN_("Track 2") " ]");
Dbhexdump(19, (uint8_t *)token, false); Dbhexdump(19, (uint8_t *)token, false);
DbpString(_YELLOW_("!!") "Card number"); DbpString("[ " _GREEN_("Card Number") " ]");
Dbhexdump(8, (uint8_t *)token, false); Dbhexdump(8, (uint8_t *)token, false);
DbpString("---"); DbpString("-------------------------------");
DbpString("");
DbpString("");
LED_C_ON(); LED_C_ON();
state = STATE_EMU; state = STATE_EMU;
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]")); DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader..."); DbpString("Waiting for a card reader...");
} }
} }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -340,14 +377,15 @@ void RunMod(void) {
// free eventually allocated BigBuf memory but keep Emulator Memory // free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) { // tag type: 11 = ISO/IEC 14443-4 - javacard (JCOP)
if (SimulateIso14443aInit(11, flags, data, &responses, &cuid, NULL, NULL, NULL) == false) {
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
DbpString(_YELLOW_("!!") "Error initializing the emulation process!"); DbpString(_RED_("Error initializing the emulation process!"));
SpinDelay(500); SpinDelay(500);
state = STATE_READ; state = STATE_READ;
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]")); DbpString("Initialized [ "_YELLOW_("reading mode") " ]");
DbpString("\n" _YELLOW_("!!") "Waiting for a Visa card..."); DbpString("Waiting for a VISA card...");
continue; continue;
} }
@ -366,11 +404,12 @@ void RunMod(void) {
for (;;) { for (;;) {
LED_B_OFF(); LED_B_OFF();
// clean receive command buffer // clean receive command buffer
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) {
DbpString(_YELLOW_("!!") "Emulator stopped"); DbpString("Emulator stopped");
retval = PM3_EOPABORTED; retval = PM3_EOPABORTED;
break; break;
} }
tag_response_info_t *p_response = NULL; tag_response_info_t *p_response = NULL;
LED_B_ON(); LED_B_ON();
@ -387,39 +426,31 @@ void RunMod(void) {
// received a HALT // received a HALT
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
//DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL; p_response = NULL;
// received a WAKEUP // received a WAKEUP
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
//DbpString(_YELLOW_("+") "WAKEUP Received");
prevCmd = 0; prevCmd = 0;
p_response = &responses[RESP_INDEX_ATQA]; p_response = &responses[RESP_INDEX_ATQA];
// received request for UID (cascade 1) // received request for UID (cascade 1)
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) {
//DbpString(_YELLOW_("+") "Request for UID C1");
p_response = &responses[RESP_INDEX_UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
// received a SELECT (cascade 1) // received a SELECT (cascade 1)
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) {
//DbpString(_YELLOW_("+") "Request for SELECT S1");
p_response = &responses[RESP_INDEX_SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
// received a RATS request // received a RATS request
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
DbpString(_YELLOW_("+") "Request for RATS");
prevCmd = 0; prevCmd = 0;
//p_response = &responses[RESP_INDEX_RATS]; p_response = &responses[RESP_INDEX_RATS];
static uint8_t rRATS[] = { 0x13, 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66, 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00, 0x90, 0x00 };
memcpy(&dynamic_response_info.response[0], rRATS, sizeof(rRATS));
dynamic_response_info.response_n = sizeof(rRATS);
} else { } else {
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]")); if (g_dbglevel == DBG_DEBUG) {
DbpString("[ "_YELLOW_("Card reader command") " ]");
Dbhexdump(len, receivedCmd, false); Dbhexdump(len, receivedCmd, false);
}
// emulate a Visa MSD (Magnetic stripe data) card // emulate a Visa MSD (Magnetic stripe data) card
if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) { if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) {
@ -428,12 +459,16 @@ void RunMod(void) {
// depending on card reader commands, the Proxmark will answer to fool the reader // depending on card reader commands, the Proxmark will answer to fool the reader
// respond with PPSE // respond with PPSE
if (receivedCmd[2] == 0xA4 && receivedCmd[6] == 0x32 && prevCmd == 0) { if (receivedCmd[2] == 0xA4 && receivedCmd[6] == 0x32 && prevCmd == 0) {
// need to adapt lengths..
uint8_t ppsea[39] = { uint8_t ppsea[39] = {
// 0x23 = 35, skip two first bytes then the message - SW 2 is 35 = 0x23
0x6F, 0x23, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59, 0x6F, 0x23, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59,
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46,
0x30, 0x31, 0xA5, 0x11, 0xBF, 0x0C, 0x0E, 0x61, 0x30, 0x31, 0xA5, 0x11, 0xBF, 0x0C, 0x0E, 0x61,
0x0C, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x4F,
0x10, 0x10, 0x87, 0x01, 0x01, 0x90, 0x00 // len aid0 aid1 aid2...
0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10,
0x87, 0x01, 0x01, 0x90, 0x00
}; };
memcpy(&dynamic_response_info.response[1], ppsea, sizeof(ppsea)); memcpy(&dynamic_response_info.response[1], ppsea, sizeof(ppsea));
dynamic_response_info.response_n = sizeof(ppsea) + 1; dynamic_response_info.response_n = sizeof(ppsea) + 1;
@ -442,10 +477,14 @@ void RunMod(void) {
// respond Visa AID // respond Visa AID
} else if (receivedCmd[2] == 0xA4 && receivedCmd[10] == 0x03 && receivedCmd[11] == 0x10 && prevCmd == 1) { } else if (receivedCmd[2] == 0xA4 && receivedCmd[10] == 0x03 && receivedCmd[11] == 0x10 && prevCmd == 1) {
uint8_t visauid_long[34] = { uint8_t visauid_long[34] = {
0x6F, 0x1E, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00, // 0x1E = 30, skip two first bytes then the message - SW 2 is 30 = 0x1E
0x03, 0x10, 0x10, 0xA5, 0x13, 0x50, 0x0B, 0x56, 0x6F, 0x1E, 0x84,
0x49, 0x53, 0x41, 0x20, 0x43, 0x52, 0x45, 0x44, // len aid0 aid1 aid2....
0x49, 0x54, 0x9F, 0x38, 0x03, 0x9F, 0x66, 0x02, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10,
0xA5, 0x13, 0x50,
// len V I S A C R E D I T
0x0B, 0x56, 0x49, 0x53, 0x41, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54,
0x9F, 0x38, 0x03, 0x9F, 0x66, 0x02,
0x90, 0x00 0x90, 0x00
}; };
memcpy(&dynamic_response_info.response[1], visauid_long, sizeof(visauid_long)); memcpy(&dynamic_response_info.response[1], visauid_long, sizeof(visauid_long));
@ -461,18 +500,21 @@ void RunMod(void) {
// SFI // SFI
} else if (receivedCmd[1] == 0x00 && receivedCmd[2] == 0xB2 && prevCmd == 3) { } else if (receivedCmd[1] == 0x00 && receivedCmd[2] == 0xB2 && prevCmd == 3) {
uint8_t last[4] = {0x70, 0x15, 0x57, 0x13}; uint8_t card[25] = {
uint8_t statusapdu[2] = {0x90, 0x00}; 0x70, 0x15, 0x57, 0x13, 0x00, 0x00, 0x00, 0x00,
uint8_t card[25]; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
memcpy(&card[0], last, sizeof(last)); 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x90, 0x00
};
// add token array == Track 2 found before
memcpy(&card[4], token, sizeof(token)); memcpy(&card[4], token, sizeof(token));
memcpy(&card[23], statusapdu, sizeof(statusapdu));
memcpy(&dynamic_response_info.response[1], card, sizeof(card)); memcpy(&dynamic_response_info.response[1], card, sizeof(card));
dynamic_response_info.response_n = sizeof(card) + 1; dynamic_response_info.response_n = sizeof(card) + 1;
prevCmd++; prevCmd++;
} else { } else {
uint8_t finished[2] = {0x6f, 0x00}; uint8_t finished[2] = {0x6F, 0x00};
memcpy(&dynamic_response_info.response[1], finished, sizeof(finished)); memcpy(&dynamic_response_info.response[1], finished, sizeof(finished));
dynamic_response_info.response_n = sizeof(finished) + 1; dynamic_response_info.response_n = sizeof(finished) + 1;
if (prevCmd == 5) { if (prevCmd == 5) {
@ -480,7 +522,7 @@ void RunMod(void) {
} }
} }
} else { } else {
DbpString(_YELLOW_("!!") "Received unknown command!"); DbpString(_RED_("Received unknown command!"));
if (prevCmd < 4) { if (prevCmd < 4) {
memcpy(dynamic_response_info.response, receivedCmd, len); memcpy(dynamic_response_info.response, receivedCmd, len);
dynamic_response_info.response_n = len; dynamic_response_info.response_n = len;
@ -491,7 +533,7 @@ void RunMod(void) {
} }
if (dynamic_response_info.response_n > 0) { if (dynamic_response_info.response_n > 0) {
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]")); DbpString("[ " _GREEN_("Proxmark3 answer") " ]");
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false); Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
DbpString("----"); DbpString("----");
@ -501,7 +543,7 @@ void RunMod(void) {
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) { if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
SpinDelay(500); SpinDelay(500);
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!"); DbpString(_RED_("Error preparing Proxmark to answer!"));
continue; continue;
} }
p_response = &dynamic_response_info; p_response = &dynamic_response_info;
@ -511,13 +553,15 @@ void RunMod(void) {
EmSendPrecompiledCmd(p_response); EmSendPrecompiledCmd(p_response);
} }
} }
switch_off();
switch_off();
set_tracing(false); set_tracing(false);
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0); reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
} }
} }
DbpString(_YELLOW_("[=]") "exiting"); DbpString("Exit standalone mode!");
DbpString("");
SpinErr(15, 200, 3);
LEDsoff(); LEDsoff();
} }

View file

@ -73,29 +73,25 @@ void ModInfo(void) {
void RunMod() { void RunMod() {
StandAloneMode(); StandAloneMode();
Dbprintf(_YELLOW_(">>") "Relaying ISO/14443A data over Bluetooth a.k.a. reblay Started<<"); DbpString("");
Dbprintf(_YELLOW_(">>> ") " Relaying ISO/14443A data over Bluetooth a.k.a. reblay Started " _YELLOW_("<<<"));
DbpString("");
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
// Such a response is less time critical, so we can prepare them on the fly
#define DYNAMIC_RESPONSE_BUFFER_SIZE 512
#define DYNAMIC_MODULATION_BUFFER_SIZE 1024
uint8_t flags = FLAG_4B_UID_IN_DATA; //UID 4 bytes(could be 7 bytes if needed it)
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; // in case there is a read command received we shouldn't break
uint8_t visauid[7] = {0x01, 0x02, 0x03, 0x04}; // UID 4 bytes(could be 7 bytes if needed it)
uint8_t flags = FLAG_4B_UID_IN_DATA;
// in case there is a read command received we shouldn't break
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t visauid[7] = {0xE9, 0x66, 0x5D, 0x20};
memcpy(data, visauid, 4); memcpy(data, visauid, 4);
// to initialize the emulation // to initialize the emulation
uint8_t tagType = 4; // 4 = ISO/IEC 14443-4 - javacard (JCOP)
tag_response_info_t *responses; tag_response_info_t *responses;
uint32_t cuid = 0; uint32_t cuid = 0;
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
uint8_t pages = 0;
// For received Bluetooth package // For received Bluetooth package
uint8_t rpacket[MAX_FRAME_SIZE] = { 0x00 }; uint8_t rpacket[MAX_FRAME_SIZE] = { 0x00 };
@ -126,6 +122,12 @@ void RunMod() {
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 }; uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 }; uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
// Such a response is less time critical, so we can prepare them on the fly
#define DYNAMIC_RESPONSE_BUFFER_SIZE 512
#define DYNAMIC_MODULATION_BUFFER_SIZE 1024
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0}; uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0}; uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
@ -143,9 +145,9 @@ void RunMod() {
uint8_t state = STATE_READ; uint8_t state = STATE_READ;
if (state == STATE_READ) { if (state == STATE_READ) {
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]")); DbpString("Initialized [ " _YELLOW_("reading mode") " ]");
} else { } else {
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]")); DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
} }
for (;;) { for (;;) {
@ -162,10 +164,10 @@ void RunMod() {
else if (button_pressed == BUTTON_SINGLE_CLICK) { // Pressing one time change between reading & emulation else if (button_pressed == BUTTON_SINGLE_CLICK) { // Pressing one time change between reading & emulation
if (state == STATE_READ) { if (state == STATE_READ) {
state = STATE_EMU; state = STATE_EMU;
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]")); DbpString("[ " _BLUE_("Emulation mode") " ]");
} else { } else {
state = STATE_READ; state = STATE_READ;
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]")); DbpString("[ " _YELLOW_("Reading mode") " ]");
} }
} }
@ -178,6 +180,7 @@ void RunMod() {
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) { if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
LED_B_ON(); LED_B_ON();
// Get data to send a ping with UID + ATQA + SAK // Get data to send a ping with UID + ATQA + SAK
@ -208,7 +211,9 @@ void RunMod() {
Dbhexdump(uidlen + 4, rdata, false); Dbhexdump(uidlen + 4, rdata, false);
DbpString(_YELLOW_("[ ") "Sending ping" _YELLOW_(" ]")); DbpString(_YELLOW_("[ ") "Sending ping" _YELLOW_(" ]"));
if (usart_writebuffer_sync(rdata, uidlen + 4) == PM3_SUCCESS) { if (usart_writebuffer_sync(rdata, uidlen + 4) == PM3_SUCCESS) {
DbpString(_YELLOW_("[ ") "Sent!" _YELLOW_(" ]")); DbpString(_YELLOW_("[ ") "Sent!" _YELLOW_(" ]"));
for (;;) { for (;;) {
@ -261,26 +266,31 @@ void RunMod() {
// free eventually allocated BigBuf memory but keep Emulator Memory // free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) { // 4 = ISO/IEC 14443-4 - javacard (JCOP)
if (SimulateIso14443aInit(4, flags, data, &responses, &cuid, NULL, NULL, NULL) == false) {
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
DbpString(_YELLOW_("!!") "Error initializing the emulation process!"); DbpString(_RED_("Error initializing the emulation process!"));
SpinDelay(500); SpinDelay(500);
state = STATE_READ; state = STATE_READ;
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]")); DbpString("Initialized [ "_YELLOW_("reading mode") " ]");
continue; continue;
} }
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
int len = 0; // Command length // Command length
int retval = PM3_SUCCESS; // Check emulation status int len = 0;
// Check emulation status
int retval = PM3_SUCCESS;
uint8_t resp = 0; // Bluetooth response // Bluetooth response
uint8_t resp = 0;
lenpacket = 0; lenpacket = 0;
uint8_t prevcmd = 0x00; // Keep track of last terminal type command // Keep track of last terminal type command
uint8_t prevcmd = 0x00;
clear_trace(); clear_trace();
set_tracing(true); set_tracing(true);
@ -288,11 +298,12 @@ void RunMod() {
for (;;) { for (;;) {
LED_B_OFF(); LED_B_OFF();
// Clean receive command buffer // Clean receive command buffer
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) {
DbpString(_YELLOW_("!!") "Emulator stopped"); DbpString("Emulator stopped");
retval = PM3_EOPABORTED; retval = PM3_EOPABORTED;
break; break;
} }
tag_response_info_t *p_response = NULL; tag_response_info_t *p_response = NULL;
LED_B_ON(); LED_B_ON();
@ -314,24 +325,18 @@ void RunMod() {
} }
} }
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
// DbpString(_YELLOW_("+") "REQUEST Received");
p_response = &responses[RESP_INDEX_ATQA]; p_response = &responses[RESP_INDEX_ATQA];
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
// DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL; p_response = NULL;
resp = 0; resp = 0;
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
// DbpString(_YELLOW_("+") "WAKEUP Received");
p_response = &responses[RESP_INDEX_ATQA]; p_response = &responses[RESP_INDEX_ATQA];
resp = 0; resp = 0;
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1) } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
// DbpString(_YELLOW_("+") "Request for UID C1");
p_response = &responses[RESP_INDEX_UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1) } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
// DbpString(_YELLOW_("+") "Request for SELECT S1");
p_response = &responses[RESP_INDEX_SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
// DbpString(_YELLOW_("+") "Request for RATS");
p_response = &responses[RESP_INDEX_RATS]; p_response = &responses[RESP_INDEX_RATS];
resp = 1; resp = 1;
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension } else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension
@ -352,8 +357,10 @@ void RunMod() {
DbpString(_YELLOW_("!!") " Avoiding request - Bluetooth data already in memory!!"); DbpString(_YELLOW_("!!") " Avoiding request - Bluetooth data already in memory!!");
} }
} else { } else {
DbpString(_GREEN_("[ ") "Card reader command" _GREEN_(" ]")); if (g_dbglevel == DBG_DEBUG) {
DbpString("[ "_YELLOW_("Card reader command") " ]");
Dbhexdump(len - 2, &receivedCmd[1], false); Dbhexdump(len - 2, &receivedCmd[1], false);
}
if ((receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) && len > 3) { // Process reader commands if ((receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) && len > 3) { // Process reader commands
@ -379,7 +386,7 @@ void RunMod() {
} else { } else {
if (lenpacket == 0) { if (lenpacket == 0) {
DbpString(_YELLOW_("!!") "Received unknown command!"); DbpString(_RED_("Received unknown command!"));
memcpy(dynamic_response_info.response, receivedCmd, len); memcpy(dynamic_response_info.response, receivedCmd, len);
dynamic_response_info.response_n = len; dynamic_response_info.response_n = len;
} else { } else {
@ -387,8 +394,9 @@ void RunMod() {
} }
} }
} }
if (dynamic_response_info.response_n > 0) { if (dynamic_response_info.response_n > 0) {
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]")); DbpString("[ " _GREEN_("Proxmark3 answer") " ]");
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false); Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
DbpString("----"); DbpString("----");
if (lenpacket > 0) { if (lenpacket > 0) {
@ -402,7 +410,7 @@ void RunMod() {
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) { if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
Dbprintf(_YELLOW_("[ ") "Buffer size: %d "_YELLOW_(" ]"), dynamic_response_info.response_n); Dbprintf(_YELLOW_("[ ") "Buffer size: %d "_YELLOW_(" ]"), dynamic_response_info.response_n);
SpinDelay(500); SpinDelay(500);
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!"); DbpString(_RED_("Error preparing Proxmark to answer!"));
continue; continue;
} }
p_response = &dynamic_response_info; p_response = &dynamic_response_info;
@ -412,13 +420,15 @@ void RunMod() {
EmSendPrecompiledCmd(p_response); EmSendPrecompiledCmd(p_response);
} }
} }
switch_off();
switch_off();
set_tracing(false); set_tracing(false);
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0); reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
} }
} }
DbpString(_YELLOW_("[=]") "exiting"); DbpString("Exit standalone mode!");
DbpString("");
SpinErr(15, 200, 3);
LEDsoff(); LEDsoff();
} }

View file

@ -62,7 +62,9 @@
#include "crc16.h" #include "crc16.h"
#include "protocols.h" #include "protocols.h"
#include "mifareutil.h" #include "mifareutil.h"
#include "sam_picopass.h"
#include "sam_seos.h"
#include "sam_mfc.h"
#ifdef WITH_LCD #ifdef WITH_LCD
#include "LCD_disabled.h" #include "LCD_disabled.h"
@ -367,11 +369,10 @@ static void print_debug_level(void) {
// measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. // measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the PacketCommandNG structure included. // Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the PacketCommandNG structure included.
static void printConnSpeed(void) { static void printConnSpeed(uint32_t wait) {
DbpString(_CYAN_("Transfer Speed")); DbpString(_CYAN_("Transfer Speed"));
Dbprintf(" Sending packets to client..."); Dbprintf(" Sending packets to client...");
#define CONN_SPEED_TEST_MIN_TIME 500 // in milliseconds
uint8_t *test_data = BigBuf_get_addr(); uint8_t *test_data = BigBuf_get_addr();
uint32_t start_time = GetTickCount(); uint32_t start_time = GetTickCount();
uint32_t delta_time = 0; uint32_t delta_time = 0;
@ -379,7 +380,7 @@ static void printConnSpeed(void) {
LED_B_ON(); LED_B_ON();
while (delta_time < CONN_SPEED_TEST_MIN_TIME) { while (delta_time < wait) {
reply_ng(CMD_DOWNLOADED_BIGBUF, PM3_SUCCESS, test_data, PM3_CMD_DATA_SIZE); reply_ng(CMD_DOWNLOADED_BIGBUF, PM3_SUCCESS, test_data, PM3_CMD_DATA_SIZE);
bytes_transferred += PM3_CMD_DATA_SIZE; bytes_transferred += PM3_CMD_DATA_SIZE;
delta_time = GetTickCountDelta(start_time); delta_time = GetTickCountDelta(start_time);
@ -388,13 +389,15 @@ static void printConnSpeed(void) {
Dbprintf(" Time elapsed................... %dms", delta_time); Dbprintf(" Time elapsed................... %dms", delta_time);
Dbprintf(" Bytes transferred.............. %d", bytes_transferred); Dbprintf(" Bytes transferred.............. %d", bytes_transferred);
Dbprintf(" Transfer Speed PM3 -> Client... " _YELLOW_("%d") " bytes/s", 1000 * bytes_transferred / delta_time); if (delta_time) {
Dbprintf(" Transfer Speed PM3 -> Client... " _YELLOW_("%llu") " bytes/s", 1000 * (uint64_t)bytes_transferred / delta_time);
}
} }
/** /**
* Prints runtime information about the PM3. * Prints runtime information about the PM3.
**/ **/
static void SendStatus(void) { static void SendStatus(uint32_t wait) {
BigBuf_print_status(); BigBuf_print_status();
Fpga_print_status(); Fpga_print_status();
#ifdef WITH_FLASH #ifdef WITH_FLASH
@ -410,7 +413,7 @@ static void SendStatus(void) {
#ifdef WITH_ISO14443a #ifdef WITH_ISO14443a
printHf14aConfig(); // HF 14a config printHf14aConfig(); // HF 14a config
#endif #endif
printConnSpeed(); printConnSpeed(wait);
DbpString(_CYAN_("Various")); DbpString(_CYAN_("Various"));
print_stack_usage(); print_stack_usage();
@ -1684,6 +1687,7 @@ static void PacketReceived(PacketCommandNG *packet) {
case CMD_HF_MIFARE_EML_MEMCLR: { case CMD_HF_MIFARE_EML_MEMCLR: {
MifareEMemClr(); MifareEMemClr();
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0); reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
break; break;
} }
case CMD_HF_MIFARE_EML_MEMSET: { case CMD_HF_MIFARE_EML_MEMSET: {
@ -2038,6 +2042,21 @@ static void PacketReceived(PacketCommandNG *packet) {
fwdata = NULL; fwdata = NULL;
break; break;
} }
case CMD_HF_SAM_PICOPASS: {
sam_picopass_get_pacs();
break;
}
case CMD_HF_SAM_SEOS: {
// sam_seos_get_pacs();
break;
}
case CMD_HF_SAM_MFC: {
// sam_mfc_get_pacs();
break;
}
#endif #endif
#ifdef WITH_FPC_USART #ifdef WITH_FPC_USART
@ -2645,7 +2664,10 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_STATUS: { case CMD_STATUS: {
SendStatus(); if (packet->length == 4)
SendStatus(packet->data.asDwords[0]);
else
SendStatus(CONN_SPEED_TEST_MIN_TIME_DEFAULT);
break; break;
} }
case CMD_TIA: { case CMD_TIA: {

View file

@ -37,6 +37,9 @@ int tearoff_hook(void);
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV // ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
#define MAX_ADC_LF_VOLTAGE 140800 #define MAX_ADC_LF_VOLTAGE 140800
// Default connection speed test timeout, used in hw status
#define CONN_SPEED_TEST_MIN_TIME_DEFAULT 500 // in milliseconds
extern int ToSendMax; extern int ToSendMax;
extern uint8_t ToSend[]; extern uint8_t ToSend[];

View file

@ -76,11 +76,11 @@ void Dbprintf(const char *fmt, ...) {
// prints HEX & ASCII // prints HEX & ASCII
void Dbhexdump(int len, const uint8_t *d, bool bAsci) { void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
#if DEBUG #if DEBUG
char ascii[9]; char ascii[17];
while (len > 0) { while (len > 0) {
int l = (len > 8) ? 8 : len; int l = (len > 16) ? 16 : len;
memcpy(ascii, d, l); memcpy(ascii, d, l);
ascii[l] = 0; ascii[l] = 0;
@ -97,33 +97,41 @@ void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
else else
Dbprintf("%*D", l, d, " "); Dbprintf("%*D", l, d, " ");
len -= 8; len -= 16;
d += 8; d += 16;
} }
#endif #endif
} }
void print_result(const char *name, const uint8_t *buf, size_t len) { void print_result(const char *name, const uint8_t *d, size_t n) {
const uint8_t *p = buf; const uint8_t *p = d;
uint16_t tmp = len & 0xFFF0; uint16_t tmp = n & 0xFFF0;
for (; p - buf < tmp; p += 16) { for (; p - d < tmp; p += 16) {
Dbprintf("[%s: %02d/%02d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", Dbprintf("[%s: %02d/%02d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
name, name,
p - buf, p - d,
len, n,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]
); );
} }
if (len % 16 != 0) {
if (n % 16 != 0) {
char s[46] = {0}; char s[46] = {0};
char *sp = s; char *sp = s;
for (; p - buf < len; p++) { for (; p - d < n; p++) {
sprintf(sp, "%02x ", p[0]); sprintf(sp, "%02x ", p[0]);
sp += 3; sp += 3;
} }
Dbprintf("[%s: %02d/%02d] %s", name, p - buf, len, s); Dbprintf("[%s: %02d/%02d] %s", name, p - d, n, s);
}
}
// Prints message and hexdump
void print_dbg(char *msg, uint8_t *d, uint16_t n) {
if (g_dbglevel == DBG_DEBUG) {
print_result(msg, d, n);
} }
} }

View file

@ -28,6 +28,7 @@ void Dbprintf(const char *fmt, ...);
void DbprintfEx(uint32_t flags, const char *fmt, ...); void DbprintfEx(uint32_t flags, const char *fmt, ...);
void Dbhexdump(int len, const uint8_t *d, bool bAsci); void Dbhexdump(int len, const uint8_t *d, bool bAsci);
void print_result(const char *name, const uint8_t *buf, size_t len); void print_result(const char *name, const uint8_t *buf, size_t len);
void print_dbg(char *msg, uint8_t *d, uint16_t n);
//void PrintToSendBuffer(void); //void PrintToSendBuffer(void);
#endif #endif

View file

@ -569,7 +569,7 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
uint8_t *spaceptr = NULL; uint8_t *spaceptr = NULL;
/* /*
keybits = malloc(2080); keybits = calloc(2080, sizeof(uint8_t));
if (!keybits) { if (!keybits) {
UserMessage("cannot malloc keybits\r\n"); UserMessage("cannot malloc keybits\r\n");
return false; return false;

View file

@ -1,4 +1,4 @@
//----------------------------------------------------------------------------- // //-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
@ -53,9 +53,6 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
#define I2C_DELAY_2CLK I2CSpinDelayClk(2) #define I2C_DELAY_2CLK I2CSpinDelayClk(2)
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) #define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
// The SIM module v4 supports up to 384 bytes for the length.
#define ISO7816_MAX_FRAME 270
// try i2c bus recovery at 100kHz = 5us high, 5us low // try i2c bus recovery at 100kHz = 5us high, 5us low
void I2C_recovery(void) { void I2C_recovery(void) {
@ -168,15 +165,15 @@ static bool WaitSCL_H_delay(uint32_t delay) {
return false; return false;
} }
// 5000 * 3.07us = 15350us. 15.35ms // 5000 * 3.07us = 15350 us = 15.35 ms
// 15000 * 3.07us = 46050us. 46.05ms // 15000 * 3.07us = 46050 us = 46.05 ms
static bool WaitSCL_H(void) { static bool WaitSCL_H(void) {
return WaitSCL_H_delay(5000); return WaitSCL_H_delay(5000);
} }
static bool WaitSCL_L_delay(uint32_t delay) { static bool WaitSCL_L_delay(uint32_t delay) {
while (delay--) { while (delay--) {
if (!SCL_read) { if (SCL_read == false) {
return true; return true;
} }
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
@ -194,7 +191,7 @@ static bool WaitSCL_L(void) {
// It timeout reading response from card // It timeout reading response from card
// Which ever comes first // Which ever comes first
static bool WaitSCL_L_timeout(void) { static bool WaitSCL_L_timeout(void) {
volatile uint32_t delay = 200; volatile uint32_t delay = 1200;
while (delay--) { while (delay--) {
// exit on SCL LOW // exit on SCL LOW
if (SCL_read == false) if (SCL_read == false)
@ -212,32 +209,41 @@ static bool I2C_Start(void) {
SDA_H; SDA_H;
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
SCL_H; SCL_H;
if (!WaitSCL_H()) if (WaitSCL_H() == false) {
return false; return false;
}
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
if (!SCL_read) if (SCL_read == false) {
return false; return false;
if (!SDA_read) }
if (SDA_read == false) {
return false; return false;
}
SDA_L; SDA_L;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
return true; return true;
} }
static bool I2C_WaitForSim(void) { static bool I2C_WaitForSim(uint32_t wait) {
// wait for data from card // wait for data from card
if (!WaitSCL_L_timeout()) if (WaitSCL_L_timeout() == false) {
return false; return false;
}
// 8051 speaks with smart card. // 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms // 1000*50*3.07 = 153.5ms
// 1000*110*3.07 = 337.7ms // 1000*110*3.07 = 337.7ms (337700)
// 4 560 000 * 3.07 = 13999,2ms (13999200)
// 1byte transfer == 1ms with max frame being 256bytes // 1byte transfer == 1ms with max frame being 256bytes
return WaitSCL_H_delay(1000 * 110);
// fct WaitSCL_H_delay uses a I2C_DELAY_1CLK in the loop with "wait" as number of iterations.
// I2C_DELAY_1CLK == I2CSpinDelayClk(1) = 3.07us
return WaitSCL_H_delay(wait);
} }
// send i2c STOP // send i2c STOP
@ -248,7 +254,11 @@ static void I2C_Stop(void) {
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
SCL_H; SCL_H;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
if (WaitSCL_H() == false) {
return;
}
SDA_H; SDA_H;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
@ -264,7 +274,11 @@ static void I2C_Ack(void) {
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
SCL_H; SCL_H;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
if (WaitSCL_H() == false) {
return;
}
SCL_L; SCL_L;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
} }
@ -277,7 +291,11 @@ static void I2C_NoAck(void) {
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
SCL_H; SCL_H;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
if (WaitSCL_H() == false) {
return;
}
SCL_L; SCL_L;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
} }
@ -288,8 +306,10 @@ static bool I2C_WaitAck(void) {
SDA_H; SDA_H;
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
SCL_H; SCL_H;
if (!WaitSCL_H())
if (WaitSCL_H() == false) {
return false; return false;
}
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
@ -302,6 +322,7 @@ static bool I2C_WaitAck(void) {
} }
static void I2C_SendByte(uint8_t data) { static void I2C_SendByte(uint8_t data) {
uint8_t bits = 8; uint8_t bits = 8;
while (bits--) { while (bits--) {
@ -319,8 +340,9 @@ static void I2C_SendByte(uint8_t data) {
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
SCL_H; SCL_H;
if (!WaitSCL_H()) if (WaitSCL_H() == false) {
return; return;
}
I2C_DELAY_2CLK; I2C_DELAY_2CLK;
} }
@ -332,111 +354,131 @@ static int16_t I2C_ReadByte(void) {
SDA_H; SDA_H;
while (bits--) { while (bits--) {
b <<= 1; b <<= 1;
SCL_L; SCL_L;
if (!WaitSCL_L()) return -2; if (WaitSCL_L() == false) {
return -2;
}
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
SCL_H; SCL_H;
if (!WaitSCL_H()) return -1; if (WaitSCL_H() == false) {
return -1;
}
I2C_DELAY_1CLK; I2C_DELAY_1CLK;
if (SDA_read) if (SDA_read) {
b |= 0x01; b |= 0x01;
} }
}
SCL_L; SCL_L;
return b; return b;
} }
// Sends one byte (command to be written, SlaveDevice address) // Sends one byte (command to be written, SlaveDevice address)
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) { bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true; bool _break = true;
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return false; return false;
}
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(device_cmd); I2C_SendByte(device_cmd);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
bBreak = false; _break = false;
} while (false); } while (false);
I2C_Stop(); I2C_Stop();
if (bBreak) {
if (_break) {
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return false; return false;
} }
return true; return true;
} }
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ). // Sends 1 byte data (data to be written, command to be written , SlaveDevice address)
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) { bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true; bool _break = true;
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return false; return false;
}
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(device_cmd); I2C_SendByte(device_cmd);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(data); I2C_SendByte(data);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
bBreak = false; _break = false;
} while (false); } while (false);
I2C_Stop(); I2C_Stop();
if (bBreak) { if (_break) {
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return false; return false;
} }
return true; return true;
} }
//Sends array of data (Array, length, command to be written , SlaveDevice address ). // Sends array of data (array, length, command to be written , SlaveDevice address)
// len = uint16 because we need to write up to 256 bytes // len = uint16 because we need to write up to 256 bytes
bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) { bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true; bool _break = true;
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return false; return false;
}
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(device_cmd); I2C_SendByte(device_cmd);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
while (len) { while (len) {
I2C_SendByte(*data); I2C_SendByte(*data);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false)
break; break;
len--; len--;
data++; data++;
} }
if (len == 0) if (len == 0) {
bBreak = false; _break = false;
}
} while (false); } while (false);
I2C_Stop(); I2C_Stop();
if (bBreak) { if (_break) {
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return false; return false;
} }
@ -447,132 +489,157 @@ bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint
// len = uint16 because we need to read up to 256bytes // len = uint16 because we need to read up to 256bytes
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) { int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
if (!data || len == 0) // sanity check
if (data == NULL || len == 0) {
return 0; return 0;
}
// uint8_t *pd = data;
// extra wait 500us (514us measured) // extra wait 500us (514us measured)
// 200us (xx measured) // 200us (xx measured)
WaitUS(600); WaitUS(600);
bool bBreak = true; bool _break = true;
uint16_t readcount = 0;
uint16_t recv_len = 0;
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return 0; return 0;
}
// 0xB0 / 0xC0 == i2c write // 0xB0 / 0xC0 == i2c write
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(device_cmd); I2C_SendByte(device_cmd);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
// 0xB1 / 0xC1 == i2c read // 0xB1 / 0xC1 == i2c read
I2C_Start(); I2C_Start();
I2C_SendByte(device_address | 1); I2C_SendByte(device_address | 1);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
bBreak = false; _break = false;
} while (false); } while (false);
if (bBreak) { if (_break) {
I2C_Stop(); I2C_Stop();
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return 0; return 0;
} }
uint16_t readcount = 0;
uint16_t recv_len = 0;
while (len) { while (len) {
int16_t tmp = I2C_ReadByte(); int16_t tmp = I2C_ReadByte();
if (tmp < 0) if (tmp < 0) {
return tmp; return tmp;
}
*data = (uint8_t)tmp & 0xFF; *data = (uint8_t)tmp & 0xFF;
len--; len--;
// Starting firmware v4 the length is encoded on the first two bytes. // Starting firmware v4 the length is encoded on the first two bytes.
// This only applies if command is I2C_DEVICE_CMD_READ.
if (device_cmd == I2C_DEVICE_CMD_READ) {
switch (readcount) { switch (readcount) {
case 0: case 0: {
// Length (MSB) // Length (MSB)
recv_len = (*data) << 8; recv_len = (*data) << 8;
break; break;
case 1: }
case 1: {
// Length (LSB) // Length (LSB)
recv_len += *data; recv_len += *data;
// old packages..
if (recv_len > 0x0200) {
// [0] = len
// [1] = data
recv_len >>= 8;
data++;
}
// Adjust len if needed // Adjust len if needed
if (len > recv_len) { if (len > recv_len) {
len = recv_len; len = recv_len;
} }
break; break;
default: }
default: {
// Data byte received // Data byte received
data++; data++;
break; break;
} }
} else {
// Length is encoded on 1 byte
if ((readcount == 0) && (len > *data)) {
len = *data;
} else {
data++;
}
} }
readcount++; readcount++;
// acknowledgements. After last byte send NACK. // acknowledgements. After last byte send NACK.
if (len == 0) if (len == 0) {
I2C_NoAck(); I2C_NoAck();
else } else {
I2C_Ack(); I2C_Ack();
} }
}
I2C_Stop(); I2C_Stop();
// Dbprintf("rec len... %u readcount... %u", recv_len, readcount);
// Dbhexdump(readcount, pd, false);
if (readcount < 2) {
return 0;
}
// return bytecount - bytes encoding length // return bytecount - bytes encoding length
return readcount - (device_cmd == I2C_DEVICE_CMD_READ ? 2 : 1); return readcount - 2;
} }
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) { int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
//START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP //START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP
bool bBreak = true; bool _break = true;
uint8_t readcount = 0; uint8_t readcount = 0;
// sending // sending
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return 0; return 0;
}
// 0xB0 / 0xC0 i2c write // 0xB0 / 0xC0 i2c write
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false)
break; break;
I2C_SendByte(msb); I2C_SendByte(msb);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(lsb); I2C_SendByte(lsb);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
// 0xB1 / 0xC1 i2c read // 0xB1 / 0xC1 i2c read
I2C_Start(); I2C_Start();
I2C_SendByte(device_address | 1); I2C_SendByte(device_address | 1);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
bBreak = false; _break = false;
} while (false); } while (false);
if (bBreak) { if (_break) {
I2C_Stop(); I2C_Stop();
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return 0; return 0;
@ -582,8 +649,9 @@ int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t
while (len) { while (len) {
int16_t tmp = I2C_ReadByte(); int16_t tmp = I2C_ReadByte();
if (tmp < 0) if (tmp < 0) {
return tmp; return tmp;
}
*data = (uint8_t)tmp & 0xFF; *data = (uint8_t)tmp & 0xFF;
@ -604,40 +672,47 @@ int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t
bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) { bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
//START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP //START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP
bool bBreak = true; bool _break = true;
do { do {
if (!I2C_Start()) if (I2C_Start() == false) {
return false; return false;
}
// 0xB0 == i2c write // 0xB0 == i2c write
I2C_SendByte(device_address & 0xFE); I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(msb); I2C_SendByte(msb);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
I2C_SendByte(lsb); I2C_SendByte(lsb);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
while (len) { while (len) {
I2C_SendByte(*data); I2C_SendByte(*data);
if (!I2C_WaitAck()) if (I2C_WaitAck() == false) {
break; break;
}
len--; len--;
data++; data++;
} }
if (len == 0) if (len == 0) {
bBreak = false; _break = false;
}
} while (false); } while (false);
I2C_Stop(); I2C_Stop();
if (bBreak) {
if (_break) {
if (g_dbglevel > 3) DbpString(I2C_ERROR); if (g_dbglevel > 3) DbpString(I2C_ERROR);
return false; return false;
} }
@ -646,37 +721,40 @@ bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uin
void I2C_print_status(void) { void I2C_print_status(void) {
DbpString(_CYAN_("Smart card module (ISO 7816)")); DbpString(_CYAN_("Smart card module (ISO 7816)"));
uint8_t maj, min;
if (I2C_get_version(&maj, &min) == PM3_SUCCESS) { uint8_t major, minor;
Dbprintf(" version................. " _YELLOW_("v%x.%02d"), maj, min); if (I2C_get_version(&major, &minor) == PM3_SUCCESS) {
if (maj < 4) {
DbpString(" " _RED_("Outdated firmware.") " Please upgrade to v4.x or above."); Dbprintf(" version................. v%d.%02d ( %s )"
} , major
, minor
, ((major == 4) && (minor == 42)) ? _GREEN_("ok") : _RED_("Outdated")
);
} else { } else {
DbpString(" version................. " _RED_("FAILED")); DbpString(" version................. ( " _RED_("fail") " )");
} }
} }
int I2C_get_version(uint8_t *maj, uint8_t *min) { int I2C_get_version(uint8_t *major, uint8_t *minor) {
uint8_t resp[] = {0, 0, 0, 0}; uint8_t resp[] = {0, 0, 0, 0};
I2C_Reset_EnterMainProgram(); I2C_Reset_EnterMainProgram();
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN); uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
if (len > 0) { if (len > 1) {
*maj = resp[0]; *major = resp[0];
*min = resp[1]; *minor = resp[1];
return PM3_SUCCESS; return PM3_SUCCESS;
} }
return PM3_EDEVNOTSUPP; return PM3_EDEVNOTSUPP;
} }
// Will read response from smart card module, retries 3 times to get the data. // Will read response from smart card module, retries 3 times to get the data.
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) { bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait) {
uint8_t i = 5; uint8_t i = 10;
int16_t len = 0; int16_t len = 0;
while (i--) { while (i--) {
I2C_WaitForSim(); I2C_WaitForSim(wait);
len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN); len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
@ -691,9 +769,9 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
} }
} }
// after three if (len < 1) {
if (len <= 1)
return false; return false;
}
*destlen = len; *destlen = len;
return true; return true;
@ -701,8 +779,10 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
bool GetATR(smart_card_atr_t *card_ptr, bool verbose) { bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
if (card_ptr == NULL) if (card_ptr == NULL) {
return false; return false;
}
card_ptr->atr_len = 0; card_ptr->atr_len = 0;
memset(card_ptr->atr, 0, sizeof(card_ptr->atr)); memset(card_ptr->atr, 0, sizeof(card_ptr->atr));
@ -713,13 +793,15 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
// wait for sim card to answer. // wait for sim card to answer.
// 1byte = 1ms , max frame 256bytes. Should wait 256ms atleast just in case. // 1byte = 1ms , max frame 256bytes. Should wait 256ms atleast just in case.
if (I2C_WaitForSim() == false) if (I2C_WaitForSim(SIM_WAIT_DELAY) == false) {
return false; return false;
}
// read bytes from module // read bytes from module
uint16_t len = sizeof(card_ptr->atr); uint16_t len = sizeof(card_ptr->atr);
if (sc_rx_bytes(card_ptr->atr, &len) == false) if (sc_rx_bytes(card_ptr->atr, &len, SIM_WAIT_DELAY) == false) {
return false; return false;
}
if (len > sizeof(card_ptr->atr)) { if (len > sizeof(card_ptr->atr)) {
len = sizeof(card_ptr->atr); len = sizeof(card_ptr->atr);
@ -803,16 +885,22 @@ void SmartCardRaw(const smart_card_raw_t *p) {
} }
} }
if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { if (((flags & SC_RAW) == SC_RAW) || ((flags & SC_RAW_T0) == SC_RAW_T0)) {
uint32_t wait = SIM_WAIT_DELAY;
if ((flags & SC_WAIT) == SC_WAIT) {
wait = (uint32_t)((p->wait_delay * 1000) / 3.07);
}
LogTrace(p->data, p->len, 0, 0, NULL, true); LogTrace(p->data, p->len, 0, 0, NULL, true);
bool res = I2C_BufferWrite( bool res = I2C_BufferWrite(
p->data, p->data,
p->len, p->len,
((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), (((flags & SC_RAW_T0) == SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND),
I2C_DEVICE_ADDRESS_MAIN I2C_DEVICE_ADDRESS_MAIN
); );
if (res == false && g_dbglevel > 3) { if (res == false && g_dbglevel > 3) {
DbpString(I2C_ERROR); DbpString(I2C_ERROR);
reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0); reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
@ -821,7 +909,7 @@ void SmartCardRaw(const smart_card_raw_t *p) {
// read bytes from module // read bytes from module
len = ISO7816_MAX_FRAME; len = ISO7816_MAX_FRAME;
res = sc_rx_bytes(resp, &len); res = sc_rx_bytes(resp, &len, wait);
if (res) { if (res) {
LogTrace(resp, len, 0, 0, NULL, false); LogTrace(resp, len, 0, 0, NULL, false);
} else { } else {

View file

@ -30,6 +30,15 @@
#define I2C_DEVICE_CMD_GETVERSION 0x06 #define I2C_DEVICE_CMD_GETVERSION 0x06
#define I2C_DEVICE_CMD_SEND_T0 0x07 #define I2C_DEVICE_CMD_SEND_T0 0x07
// The SIM module v4 supports up to 384 bytes for the length.
#define ISO7816_MAX_FRAME 270
// 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms
// 1 byte transfer == 1ms with max frame being 256 bytes
#define SIM_WAIT_DELAY 88000 // about 270ms delay // 109773 -- about 337.7ms delay
void I2C_recovery(void); void I2C_recovery(void);
void I2C_init(bool has_ticks); void I2C_init(bool has_ticks);
void I2C_Reset(void); void I2C_Reset(void);
@ -48,7 +57,7 @@ int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address); int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address); bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen); bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait);
// //
bool GetATR(smart_card_atr_t *card_ptr, bool verbose); bool GetATR(smart_card_atr_t *card_ptr, bool verbose);

View file

@ -36,9 +36,10 @@
#include "protocols.h" #include "protocols.h"
#include "ticks.h" #include "ticks.h"
#include "iso15693.h" #include "iso15693.h"
#include "iclass_cmd.h" /* iclass_card_select_t struct */ #include "iclass_cmd.h" // iclass_card_select_t struct
#include "i2c.h" // i2c defines (SIM module access)
static uint8_t get_pagemap(const picopass_hdr_t *hdr) { uint8_t get_pagemap(const picopass_hdr_t *hdr) {
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
} }
@ -52,23 +53,6 @@ static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
#define ICLASS_16KS_SIZE 0x100 * 8 #define ICLASS_16KS_SIZE 0x100 * 8
#endif #endif
// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after
// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period.
// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating.
// 56,64us = 24 ssp_clk_cycles
#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 26) // (140 - 24)
// times in ssp_clk_cycles @ 3,3625MHz when acting as reader
#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER
// times in samples @ 212kHz when acting as reader
#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us
#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms
#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us
#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
/* /*
* CARD TO READER * CARD TO READER
* in ISO15693-2 mode - Manchester * in ISO15693-2 mode - Manchester
@ -1245,7 +1229,7 @@ send:
} }
// THE READER CODE // THE READER CODE
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) { void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) {
CodeIso15693AsReader(frame, len); CodeIso15693AsReader(frame, len);
tosend_t *ts = get_tosend(); tosend_t *ts = get_tosend();
TransmitTo15693Tag(ts->buf, ts->max, start_time, shallow_mod); TransmitTo15693Tag(ts->buf, ts->max, start_time, shallow_mod);
@ -1784,7 +1768,6 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
return false; return false;
} }
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (blockno == 2) { if (blockno == 2) {
// check response. e-purse update swaps first and second half // check response. e-purse update swaps first and second half
if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) { if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) {
@ -1792,6 +1775,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
} }
} else if (blockno == 3 || blockno == 4) { } else if (blockno == 3 || blockno == 4) {
// check response. Key updates always return 0xffffffffffffffff // check response. Key updates always return 0xffffffffffffffff
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (memcmp(all_ff, resp, 8)) { if (memcmp(all_ff, resp, 8)) {
return false; return false;
} }
@ -1821,7 +1805,7 @@ void iClass_WriteBlock(uint8_t *msg) {
// select tag. // select tag.
uint32_t eof_time = 0; uint32_t eof_time = 0;
picopass_hdr_t hdr = {0}; picopass_hdr_t hdr = {0};
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod); bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
if (res == false) { if (res == false) {
goto out; goto out;
} }
@ -1881,8 +1865,9 @@ void iClass_WriteBlock(uint8_t *msg) {
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false; res = false;
switch_off(); switch_off();
if (payload->req.send_reply) if (payload->req.send_reply) {
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t)); reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(bool));
}
return; return;
} else { } else {
@ -1901,16 +1886,16 @@ void iClass_WriteBlock(uint8_t *msg) {
} }
// verify write // verify write
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; if ((pagemap != PICOPASS_NON_SECURE_PAGEMODE) && (payload->req.blockno == 2)) {
if (pagemap == PICOPASS_SECURE_PAGEMODE && payload->req.blockno == 2) {
// check response. e-purse update swaps first and second half // check response. e-purse update swaps first and second half
if (memcmp(payload->data + 4, resp, 4) || memcmp(payload->data, resp + 4, 4)) { if (memcmp(payload->data + 4, resp, 4) || memcmp(payload->data, resp + 4, 4)) {
res = false; res = false;
goto out; goto out;
} }
} else if (pagemap == PICOPASS_SECURE_PAGEMODE && (payload->req.blockno == 3 || payload->req.blockno == 4)) { } else if ((pagemap != PICOPASS_NON_SECURE_PAGEMODE) && (payload->req.blockno == 3 || payload->req.blockno == 4)) {
// check response. Key updates always return 0xffffffffffffffff // check response. Key updates always return 0xffffffffffffffff
if (memcmp(all_ff, resp, 8)) { uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (memcmp(all_ff, resp, sizeof(all_ff))) {
res = false; res = false;
goto out; goto out;
} }
@ -1925,8 +1910,9 @@ void iClass_WriteBlock(uint8_t *msg) {
out: out:
switch_off(); switch_off();
if (payload->req.send_reply) if (payload->req.send_reply) {
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(bool));
}
} }
void iclass_credit_epurse(iclass_credit_epurse_t *payload) { void iclass_credit_epurse(iclass_credit_epurse_t *payload) {
@ -1967,8 +1953,9 @@ void iclass_credit_epurse(iclass_credit_epurse_t *payload) {
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), epurse, sizeof(epurse), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod); res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), epurse, sizeof(epurse), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
if (!res) { if (!res) {
switch_off(); switch_off();
if (payload->req.send_reply) if (payload->req.send_reply) {
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETIMEOUT, (uint8_t *)&res, sizeof(uint8_t)); reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETIMEOUT, (uint8_t *)&res, sizeof(uint8_t));
}
return; return;
} }
@ -1977,7 +1964,7 @@ void iclass_credit_epurse(iclass_credit_epurse_t *payload) {
uint8_t epurse_offset = 0; uint8_t epurse_offset = 0;
const uint8_t empty_epurse[] = {0xff, 0xff, 0xff, 0xff}; const uint8_t empty_epurse[] = {0xff, 0xff, 0xff, 0xff};
if (!memcmp(epurse, empty_epurse, 4)) { if (memcmp(epurse, empty_epurse, 4) == 0) {
// epurse data in stage 2 // epurse data in stage 2
epurse_offset = 4; epurse_offset = 4;
} }

View file

@ -21,6 +21,23 @@
#include "common.h" #include "common.h"
#include "iclass_cmd.h" #include "iclass_cmd.h"
// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after
// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period.
// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating.
// 56,64us = 24 ssp_clk_cycles
#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 26) // (140 - 24)
// times in ssp_clk_cycles @ 3,3625MHz when acting as reader
#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER
// times in samples @ 212kHz when acting as reader
#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us
#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms
#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us
#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
void ReaderIClass(uint8_t flags); void ReaderIClass(uint8_t flags);
@ -43,4 +60,7 @@ bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, ui
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod); bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod);
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
uint8_t get_pagemap(const picopass_hdr_t *hdr);
void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod);
#endif #endif

View file

@ -1021,7 +1021,8 @@ bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_
} }
} }
bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_response_info_t **responses, uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) { bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_response_info_t **responses,
uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) {
uint8_t sak = 0; uint8_t sak = 0;
// The first response contains the ATQA (note: bytes are transmitted in reverse order). // The first response contains the ATQA (note: bytes are transmitted in reverse order).
static uint8_t rATQA[2] = { 0x00 }; static uint8_t rATQA[2] = { 0x00 };
@ -1038,8 +1039,13 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// Prepare the optional third SAK (for 10 byte UID), drop the cascade bit // Prepare the optional third SAK (for 10 byte UID), drop the cascade bit
static uint8_t rSAKc3[3] = { 0x00 }; static uint8_t rSAKc3[3] = { 0x00 };
// dummy ATS (pseudo-ATR), answer to RATS // dummy ATS (pseudo-ATR), answer to RATS
// Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
// TC(1) = 0x02: CID supported, NAD not supported
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 }; static uint8_t rRATS[40] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00, 0x00 };
uint8_t rRATS_len = 8;
// GET_VERSION response for EV1/NTAG // GET_VERSION response for EV1/NTAG
static uint8_t rVERSION[10] = { 0x00 }; static uint8_t rVERSION[10] = { 0x00 };
@ -1092,6 +1098,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
rATQA[1] = 0x03; rATQA[1] = 0x03;
sak = 0x20; sak = 0x20;
memcpy(rRATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8); memcpy(rRATS, "\x06\x75\x77\x81\x02\x80\x00\x00", 8);
rRATS_len = 8;
break; break;
} }
case 4: { // ISO/IEC 14443-4 - javacard (JCOP) case 4: { // ISO/IEC 14443-4 - javacard (JCOP)
@ -1158,7 +1165,10 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
sak = 0x20; sak = 0x20;
break; break;
} }
case 11: { // ISO/IEC 14443-4 - javacard (JCOP) case 11: { // ISO/IEC 14443-4 - javacard (JCOP) / EMV
memcpy(rRATS, "\x13\x78\x80\x72\x02\x80\x31\x80\x66\xb1\x84\x0c\x01\x6e\x01\x83\x00\x90\x00", 19);
rRATS_len = 19;
rATQA[0] = 0x04; rATQA[0] = 0x04;
sak = 0x20; sak = 0x20;
break; break;
@ -1266,11 +1276,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
return false; return false;
} }
// Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, AddCrc14A(rRATS, rRATS_len - 2);
// TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1
// TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us)
// TC(1) = 0x02: CID supported, NAD not supported
AddCrc14A(rRATS, sizeof(rRATS) - 2);
AddCrc14A(rPPS, sizeof(rPPS) - 2); AddCrc14A(rPPS, sizeof(rPPS) - 2);
@ -1305,14 +1311,23 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
{ .response = rPACK, .response_n = sizeof(rPACK) } // PACK response { .response = rPACK, .response_n = sizeof(rPACK) } // PACK response
}; };
// "precompile" responses. There are 12 predefined responses with a total of 84 bytes data to transmit. // since rats len is variable now.
responses_init[RESP_INDEX_RATS].response_n = rRATS_len;
// "precompiled" responses.
// These exist for speed reasons. There are no time in the anti collision phase to calculate responses.
// There are 12 predefined responses with a total of 84 bytes data to transmit.
//
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits // 85 * 8 data bits, 85 * 1 parity bits, 12 start bits, 12 stop bits, 12 correction bits
// 85 * 8 + 85 + 12 + 12 + 12 == 801 // 85 * 8 + 85 + 12 + 12 + 12 == 801
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 801 // CHG:
// 85 bytes normally (rats = 8 bytes)
// 77 bytes + ratslen,
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE ( ((77 + rRATS_len) * 8) + 77 + rRATS_len + 12 + 12 + 12)
uint8_t *free_buffer = BigBuf_calloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
// modulation buffer pointer and current buffer free space size // modulation buffer pointer and current buffer free space size
uint8_t *free_buffer_pointer = free_buffer; uint8_t *free_buffer_pointer = free_buffer;
size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE;
@ -1328,7 +1343,6 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
} }
*responses = responses_init; *responses = responses_init;
return true; return true;
} }
@ -1362,12 +1376,16 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 }; uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 }; uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
// free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM();
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it // Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
// Such a response is less time critical, so we can prepare them on the fly // Such a response is less time critical, so we can prepare them on the fly
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64 #define DYNAMIC_RESPONSE_BUFFER_SIZE 64
#define DYNAMIC_MODULATION_BUFFER_SIZE 512 #define DYNAMIC_MODULATION_BUFFER_SIZE 512
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0}; uint8_t *dynamic_response_buffer = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
uint8_t *dynamic_modulation_buffer = BigBuf_calloc(DYNAMIC_MODULATION_BUFFER_SIZE);
tag_response_info_t dynamic_response_info = { tag_response_info_t dynamic_response_info = {
.response = dynamic_response_buffer, .response = dynamic_response_buffer,
.response_n = 0, .response_n = 0,
@ -1375,9 +1393,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_
.modulation_n = 0 .modulation_n = 0
}; };
// free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM();
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) { if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
BigBuf_free_keep_EM(); BigBuf_free_keep_EM();
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);

View file

@ -1060,7 +1060,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
if (dtf->len > dtf->max_len) { if (dtf->len > dtf->max_len) {
ret = PM3_EOVFLOW; ret = PM3_EOVFLOW;
Dbprintf("overflow (%d > %d", dtf->len, dtf->max_len); Dbprintf("overflow (%d > %d)", dtf->len, dtf->max_len);
} }
break; break;
} }
@ -1083,7 +1083,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
if (dt->len > dt->max_len) { if (dt->len > dt->max_len) {
ret = PM3_EOVFLOW; ret = PM3_EOVFLOW;
Dbprintf("overflow (%d > %d", dt->len, dt->max_len); Dbprintf("overflow (%d > %d)", dt->len, dt->max_len);
} }
break; break;
} }

View file

@ -128,20 +128,6 @@ sample_config *getSamplingConfig(void) {
return &config; return &config;
} }
/**
* @brief Pushes bit onto the stream
* @param stream
* @param bit
*/
static void pushBit(BitstreamOut_t *stream, uint8_t bit) {
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer + bytepos) &= ~(1 << (7 - bitpos));
*(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
void initSampleBuffer(uint32_t *sample_size) { void initSampleBuffer(uint32_t *sample_size) {
initSampleBufferEx(sample_size, false); initSampleBufferEx(sample_size, false);
} }
@ -233,13 +219,20 @@ void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool
data.numbits = samples.total_saved << 3; data.numbits = samples.total_saved << 3;
} else { } else {
pushBit(&data, sample & 0x80); // truncate trailing data
if (bits_per_sample > 1) pushBit(&data, sample & 0x40); sample >>= 8 - bits_per_sample;
if (bits_per_sample > 2) pushBit(&data, sample & 0x20); sample <<= 8 - bits_per_sample;
if (bits_per_sample > 3) pushBit(&data, sample & 0x10);
if (bits_per_sample > 4) pushBit(&data, sample & 0x08); uint8_t bits_offset = data.numbits & 0x7;
if (bits_per_sample > 5) pushBit(&data, sample & 0x04); uint8_t bits_cap = 8 - bits_offset;
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
// write the current byte
data.buffer[data.numbits >> 3] |= sample >> bits_offset;
int numbits = data.numbits + bits_cap;
// write the remaining bits to the next byte
data.buffer[numbits >> 3] |= sample << (bits_cap);
data.numbits += bits_per_sample;
} }
} }

23
armsrc/sam_mfc.c Normal file
View file

@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Routines to support MFC <-> SAM communication
//-----------------------------------------------------------------------------
#include "sam_mfc.h"
#include "sam_seos.h"
#include "iclass.h"
#include "proxmark3_arm.h"
#include "cmd.h"

21
armsrc/sam_mfc.h Normal file
View file

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
#ifndef __SAM_MFC_H
#define __SAM_MFC_H
#include "common.h"
#endif

447
armsrc/sam_picopass.c Normal file
View file

@ -0,0 +1,447 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Routines to support Picopass <-> SAM communication
//-----------------------------------------------------------------------------
#include "sam_picopass.h"
#include "iclass.h"
#include "crc16.h"
#include "proxmark3_arm.h"
#include "BigBuf.h"
#include "cmd.h"
#include "commonutil.h"
#include "ticks.h"
#include "dbprint.h"
#include "i2c.h"
#include "iso15693.h"
#include "protocols.h"
#include "optimized_cipher.h"
#include "fpgaloader.h"
static int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) {
StartTicks();
bool res = I2C_BufferWrite(data, n, I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN);
if (res == false) {
DbpString("failed to send to SIM CARD");
goto out;
}
*resplen = ISO7816_MAX_FRAME;
res = sc_rx_bytes(resp, resplen, SIM_WAIT_DELAY);
if (res == false) {
DbpString("failed to receive from SIM CARD");
goto out;
}
if (*resplen < 2) {
DbpString("received too few bytes from SIM CARD");
res = false;
goto out;
}
uint16_t more_len = 0;
if (resp[*resplen - 2] == 0x61 || resp[*resplen - 2] == 0x9F) {
more_len = resp[*resplen - 1];
} else {
// we done, return
goto out;
}
// Don't discard data we already received except the SW code.
// If we only received 1 byte, this is the echo of INS, we discard it.
*resplen -= 2;
if (*resplen == 1) {
*resplen = 0;
}
uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len};
res = I2C_BufferWrite(cmd_getresp, sizeof(cmd_getresp), I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN);
if (res == false) {
DbpString("failed to send to SIM CARD 2");
goto out;
}
more_len = 255 - *resplen;
res = sc_rx_bytes(resp + *resplen, &more_len, SIM_WAIT_DELAY);
if (res == false) {
DbpString("failed to receive from SIM CARD 2");
goto out;
}
*resplen += more_len;
out:
StopTicks();
return res;
}
// using HID SAM to authenticate w PICOPASS
int sam_picopass_get_pacs(void) {
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 };
uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64};
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
picopass_hdr_t hdr = {0};
// Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
// bit 7: parity.
// if (use_credit_key)
// read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
BigBuf_free_keep_EM();
clear_trace();
I2C_Reset_EnterMainProgram();
StopTicks();
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
bool shallow_mod = false;
uint16_t resp_len = 0;
int res;
uint32_t eof_time = 0;
// wakeup
Iso15693InitReader();
uint32_t start_time = GetCountSspClk();
iclass_send_as_reader(act_all, 1, &start_time, &eof_time, shallow_mod);
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_ACTALL, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// send Identify
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(identify, 1, &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 10) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// copy the Anti-collision CSN to our select-packet
memcpy(&select[1], resp, 8);
// select the card
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(select, sizeof(select), &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 10) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// store CSN
memcpy(hdr.csn, resp, sizeof(hdr.csn));
// card selected, now read config (block1) (only 8 bytes no CRC)
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, &eof_time, shallow_mod);
// expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 10) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// store CONFIG
memcpy((uint8_t *)&hdr.conf, resp, sizeof(hdr.conf));
uint8_t pagemap = get_pagemap(&hdr);
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
res = PM3_EWRONGANSWER;
goto out;
}
// read App Issuer Area block 5
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 10) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// store AIA
memcpy(hdr.app_issuer_area, resp, sizeof(hdr.app_issuer_area));
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
// expect a 8-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 8) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// store EPURSE
memcpy(hdr.epurse, resp, sizeof(hdr.epurse));
// -----------------------------------------------------------------------------
// SAM comms
// -----------------------------------------------------------------------------
size_t sam_len = 0;
uint8_t *sam_apdu = BigBuf_calloc(ISO7816_MAX_FRAME);
// -----------------------------------------------------------------------------
// first
// a0 da 02 63 1a 44 0a 44 00 00 00 a0 12 ad 10 a0 0e 80 02 00 04 81 08 9b fc a4 00 fb ff 12 e0
hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu, &sam_len);
memcpy(sam_apdu + sam_len, hdr.csn, sizeof(hdr.csn));
sam_len += sizeof(hdr.csn);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 1", resp, resp_len);
// -----------------------------------------------------------------------------
// second
// a0 da 02 63 0d 44 0a 44 00 00 00 a0 05 a1 03 80 01 04
hexstr_to_byte_array("a0da02630d440a44000000a005a103800104", sam_apdu, &sam_len);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 2", resp, resp_len);
// TAG response
// -- 0c 05 de64 // read block 5
// Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4
// -----------------------------------------------------------------------------
// third AIA block 5
// a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000
// picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5
// picpoasss SE ff ff ff 00 06 ff ff ff f8 8e
hexstr_to_byte_array("a0da02631c140a00000000bd14a012a010800affffff0006fffffff88e81020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, hdr.app_issuer_area, sizeof(hdr.app_issuer_area));
AddCrc(sam_apdu + 19, 8);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 3", resp, resp_len);
// 88 02 -- readcheck (block2 epurse, start of auth)
// Tag|c00a140a000000a10ea10c8002 8802 8102 0004 820201f4 9000
// 61 16 f5 0a140a000000a10ea10c 8002 8802 8102 0004 820201f4 9000
// -----------------------------------------------------------------------------
// forth EPURSE
// a0da02631a140a00000000bd12a010a00e8008 ffffffffedffffff 81020000
hexstr_to_byte_array("a0da02631a140a00000000bd12a010a00e8008ffffffffedffffff81020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, hdr.epurse, sizeof(hdr.epurse));
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 4", resp, resp_len);
uint8_t nr_mac[9] = {0};
memcpy(nr_mac, resp + 11, sizeof(nr_mac));
// resp here hold the whole NR/MAC
// 05 9bcd475e965ee20e // CHECK (w key)
print_dbg("NR/MAC", nr_mac, sizeof(nr_mac));
// c00a140a000000a115a1138009 059bcd475e965ee20e 8102 0004 820201f4 9000
// pre calc ourself?
// uint8_t cc_nr[] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};
uint8_t div_key[8] = {0};
static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78};
iclass_calc_div_key(hdr.csn, legacy_aa1_key, div_key, false);
uint8_t mac[4] = {0};
if (g_dbglevel == DBG_DEBUG) {
uint8_t wb[16] = {0};
memcpy(wb, hdr.epurse, sizeof(hdr.epurse));
memcpy(wb + sizeof(hdr.epurse), nr_mac + 1, 4);
print_dbg("cc_nr...", wb, sizeof(wb));
doMAC_N(wb, sizeof(wb), div_key, mac);
print_dbg("Calc MAC...", mac, sizeof(mac));
}
// start ssp clock again...
StartCountSspClk();
// NOW we auth against tag
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
memcpy(cmd_check + 1, nr_mac + 1, 8);
start_time = GetCountSspClk();
iclass_send_as_reader(cmd_check, sizeof(cmd_check), &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 4) {
res = PM3_ECARDEXCHANGE;
goto out;
}
// store MAC
memcpy(mac, resp, sizeof(mac));
print_dbg("Got MAC", mac, sizeof(mac));
// -----------------------------------------------------------------------------
// fifth send received MAC
// A0DA026316140A00000000BD0EA00CA00A8004 311E32E9 81020000
hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, mac, sizeof(mac));
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 5", resp, resp_len);
uint8_t tmp_p1[4] = {0};
uint8_t tmp_p2[4] = {0};
// c161c10000a11aa118800e8702 ffffffff88ffffff 0a914eb981020004820236b09000
memcpy(tmp_p1, resp + 13, sizeof(tmp_p1));
memcpy(tmp_p2, resp + 13 + 4, sizeof(tmp_p2));
// -----------------------------------------------------------------------------
// sixth send fake epurse update
// A0DA02631C140A00000000BD14A012A010800A 88FFFFFFFFFFFFFF9DE1 81020000
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A88FFFFFFFFFFFFFF9DE181020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, tmp_p2, sizeof(tmp_p1));
memcpy(sam_apdu + 19 + 4, tmp_p1, sizeof(tmp_p1));
AddCrc(sam_apdu + 19, 8);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 6", resp, resp_len);
// c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00
// read block 6
StartCountSspClk();
start_time = GetCountSspClk();
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS || resp_len != 10) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("Block 6 from Picopass", resp, resp_len);
// -----------------------------------------------------------------------------
// eight send block 6 config to SAM
// A0DA02631C140A00000000BD14A012A010800A 030303030003E0174323 81020000
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, resp, resp_len);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 7", resp, resp_len);
// c161c10000a110a10e8004 0606455681020004820201f49000
// read the credential blocks
StartCountSspClk();
start_time = GetCountSspClk();
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
// expect a 10-byte response here
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res != PM3_SUCCESS) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("Block 6-9 from Picopass", resp, resp_len);
// -----------------------------------------------------------------------------
// nine send credential blocks to SAM
// A0DA026334140A00000000BD2CA02AA0288022 030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C 81020000
hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, resp, resp_len);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 8", resp, resp_len);
// -----------------------------------------------------------------------------
// TEN ask for PACS data
// A0DA02630C440A00000000BD04A0028200
hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu, &sam_len);
memcpy(sam_apdu + 19, resp, resp_len);
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
res = PM3_ECARDEXCHANGE;
goto out;
}
print_dbg("-- 9 response", resp, resp_len);
if (memcmp(resp, "\xc1\x64\x00\x00\x00\xbd\x17\x8a\x15", 9) == 0) {
res = PM3_ENOPACS;
goto out;
}
// c164000000bd098a07 030506951f9a00 9000
uint8_t *pacs = BigBuf_calloc(resp[8]);
memcpy(pacs, resp + 9, resp[8]);
print_dbg("-- 10 PACS data", pacs, resp[8]);
reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, pacs, resp[8]);
res = PM3_SUCCESS;
goto off;
out:
reply_ng(CMD_HF_SAM_PICOPASS, res, NULL, 0);
off:
switch_off();
BigBuf_free();
return res;
}
// HID SAM <-> MFC
// HID SAM <-> SEOS

23
armsrc/sam_picopass.h Normal file
View file

@ -0,0 +1,23 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
#ifndef __SAM_PICOPASS_H
#define __SAM_PICOPASS_H
#include "common.h"
int sam_picopass_get_pacs(void);
#endif

22
armsrc/sam_seos.c Normal file
View file

@ -0,0 +1,22 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Routines to support SEOS <-> SAM communication
//-----------------------------------------------------------------------------
#include "sam_seos.h"
#include "iclass.h"
#include "proxmark3_arm.h"
#include "cmd.h"

21
armsrc/sam_seos.h Normal file
View file

@ -0,0 +1,21 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
#ifndef __SAM_SEOS_H
#define __SAM_SEOS_H
#include "common.h"
#endif

View file

@ -279,6 +279,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifare4.c
${PM3_ROOT}/client/src/mifare/mifaredefault.c ${PM3_ROOT}/client/src/mifare/mifaredefault.c
${PM3_ROOT}/client/src/mifare/mifarehost.c ${PM3_ROOT}/client/src/mifare/mifarehost.c
${PM3_ROOT}/client/src/mifare/gen4.c
${PM3_ROOT}/client/src/nfc/ndef.c ${PM3_ROOT}/client/src/nfc/ndef.c
${PM3_ROOT}/client/src/mifare/lrpcrypto.c ${PM3_ROOT}/client/src/mifare/lrpcrypto.c
${PM3_ROOT}/client/src/mifare/desfirecrypto.c ${PM3_ROOT}/client/src/mifare/desfirecrypto.c
@ -286,6 +287,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/uart/ringbuffer.c
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui

View file

@ -371,12 +371,16 @@ ifeq ($(PYTHON_FOUND),1)
endif endif
####################################################################################################### #######################################################################################################
# macOS doesn't like this params
#MYCFLAGS += --param max-completely-peeled-insns=1000 --param max-completely-peel-times=10000
MYCFLAGS += -O3
CFLAGS ?= $(DEFCFLAGS) CFLAGS ?= $(DEFCFLAGS)
CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES) CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES)
# We cannot just use CFLAGS+=... because it has impact on sub-makes if CFLAGS is defined in env: # We cannot just use CFLAGS+=... because it has impact on sub-makes if CFLAGS is defined in env:
PM3CFLAGS = $(CFLAGS) PM3CFLAGS = $(CFLAGS)
PM3CFLAGS += -g -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES) PM3CFLAGS += -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES)
# WIP Testing # WIP Testing
#PM3CFLAGS += -std=c11 -pedantic #PM3CFLAGS += -std=c11 -pedantic
@ -415,7 +419,7 @@ endif
PM3CFLAGS += -DHAVE_SNPRINTF PM3CFLAGS += -DHAVE_SNPRINTF
CXXFLAGS ?= -Wall -Werror -O3 CXXFLAGS ?= -Wall -Werror
CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES) CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES)
PM3CXXFLAGS = $(CXXFLAGS) PM3CXXFLAGS = $(CXXFLAGS)
@ -699,6 +703,7 @@ SRCS = mifare/aiddesfire.c \
mifare/mifare4.c \ mifare/mifare4.c \
mifare/mifaredefault.c \ mifare/mifaredefault.c \
mifare/mifarehost.c \ mifare/mifarehost.c \
mifare/gen4.c \
nfc/ndef.c \ nfc/ndef.c \
pm3.c \ pm3.c \
pm3_binlib.c \ pm3_binlib.c \
@ -707,6 +712,7 @@ SRCS = mifare/aiddesfire.c \
pm3line.c \ pm3line.c \
proxmark3.c \ proxmark3.c \
scandir.c \ scandir.c \
uart/ringbuffer.c \
uart/uart_posix.c \ uart/uart_posix.c \
uart/uart_win32.c \ uart/uart_win32.c \
scripting.c \ scripting.c \

View file

@ -59,6 +59,7 @@ const char *getAtrInfo(const char *atr_str);
// atr_t array is expected to be NULL terminated // atr_t array is expected to be NULL terminated
const static atr_t AtrTable[] = { const static atr_t AtrTable[] = {
{ "3BDF18FFC080B1FE751F033078464646462026204963656D616E1D", "Cardhelper by 0xFFFF and Iceman" }, { "3BDF18FFC080B1FE751F033078464646462026204963656D616E1D", "Cardhelper by 0xFFFF and Iceman" },
{ "3B90969181B1FE551FC7D4", "IClass SE Processor (Other) https://www.hidglobal.com/products/embedded-modules/iclass-se/sio-processor"},
""" """
C_FOOTER=""" {NULL, "N/A"} C_FOOTER=""" {NULL, "N/A"}

View file

@ -147,6 +147,7 @@ enum ParserState {
PS_FIRST, PS_FIRST,
PS_ARGUMENT, PS_ARGUMENT,
PS_OPTION, PS_OPTION,
PS_QUOTE,
}; };
#define isSpace(c)(c == ' ' || c == '\t') #define isSpace(c)(c == ' ' || c == '\t')
@ -195,6 +196,10 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
case PS_ARGUMENT: case PS_ARGUMENT:
if (state == PS_FIRST) if (state == PS_FIRST)
state = PS_ARGUMENT; state = PS_ARGUMENT;
if (str[i] == '"') {
state = PS_QUOTE;
break;
}
if (isSpace(str[i])) { if (isSpace(str[i])) {
spaceptr = bufptr; spaceptr = bufptr;
state = PS_FIRST; state = PS_FIRST;
@ -215,6 +220,16 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab
*bufptr = str[i]; *bufptr = str[i];
bufptr++; bufptr++;
break; break;
case PS_QUOTE:
if (str[i] == '"') {
*bufptr++ = 0x00;
state = PS_FIRST;
} else {
if (isSpace(str[i]) == false) {
*bufptr++ = str[i];
}
}
break;
} }
if (bufptr > bufptrend) { if (bufptr > bufptrend) {
PrintAndLogEx(ERR, "ERROR: Line too long\n"); PrintAndLogEx(ERR, "ERROR: Line too long\n");

View file

@ -141,6 +141,10 @@ F1D83F964314
FFF011223358 FFF011223358
FF9F11223358 FF9F11223358
# #
# Elevator system Kherson, Ukraine
AC37E76385F5
576DCFFF2F25
#
# more Keys from mfc_default_keys.lua # more Keys from mfc_default_keys.lua
000000000001 000000000001
000000000002 000000000002
@ -966,7 +970,7 @@ D58660D1ACDE
C01FC822C6E5 C01FC822C6E5
0854BF31111E 0854BF31111E
# #
# More keys # More keys - Found 8A at Sebel Hotel in Canberra, Australia
8A19D40CF2B5 8A19D40CF2B5
AE8587108640 AE8587108640
# #
@ -1029,6 +1033,10 @@ F8493407799D
6B8BD9860763 6B8BD9860763
D3A297DC2698 D3A297DC2698
# #
# Data from reddit
34635A313344
593367486137
#
# Keys from Mifare Classic Tool project # Keys from Mifare Classic Tool project
044CE1872BC3 044CE1872BC3
045CECA15535 045CECA15535
@ -1829,11 +1837,17 @@ E19504C39461
FA1FBB3F0F1F FA1FBB3F0F1F
FF16014FEFC7 FF16014FEFC7
# #
#
# Food GEM # Food GEM
6686FADE5566 6686FADE5566
# #
# Samsung Data Systems (SDS) — Electronic Locks
# Gen 1 S10 KA/KB is FFFFFFFFFFFF, incompatible with Gen 2 locks
#
# SDS Gen 2 S10 KB
C22E04247D9A
#
# Data from Discord, French pool # Data from Discord, French pool
# SDS Gen 2 S10 KA
9B7C25052FC3 9B7C25052FC3
494446555455 494446555455
# #
@ -2093,6 +2107,45 @@ D144BD193063
# Unknown hotel system Sec 0 / A # Unknown hotel system Sec 0 / A
353038383134 353038383134
# #
# Brazil transport Sec 8 / A
50d4c54fcdf5
#
# Bandai Namco Passport [fka Banapassport] / Sega Aime Card
# Dumped on the Flipper Devices Discord Server
6090D00632F5
019761AA8082
574343467632
A99164400748
62742819AD7C
CC5075E42BA1
B9DF35A0814C
8AF9C718F23D
58CD5C3673CB
FC80E88EB88C
7A3CDAD7C023
30424C029001
024E4E44001F
ECBBFA57C6AD
4757698143BD
1D30972E6485
F8526D1A8D6D
1300EC8C7E80
F80A65A87FFA
DEB06ED4AF8E
4AD96BF28190
000390014D41
0800F9917CB0
730050555253
4146D4A956C4
131157FBB126
E69DD9015A43
337237F254D5
9A8389F32FBF
7B8FB4A7100B
C8382A233993
7B304F2A12A6
FC9418BF788B
#
# Data from "the more the marriott" mifare project (colonelborkmundus) # Data from "the more the marriott" mifare project (colonelborkmundus)
# aka The Horde # aka The Horde
# #
@ -2225,3 +2278,13 @@ EDC317193709
A1670589B2AF A1670589B2AF
# SF Hotel (SoMa area) # SF Hotel (SoMa area)
2E0F00700000 2E0F00700000
#
# Unknown PACS from Western Australia
CA80E51FA52B
A71E80EA35E1
05597810D63D
#
# Hotel Key from Las Vegas
EA0CA627FD06
80BB8436024C
5044068C5183

View file

@ -166,11 +166,12 @@ endif (NOT SKIPJANSSONSYSTEM EQUAL 1)
if(EMBED_BZIP2) if(EMBED_BZIP2)
cmake_policy(SET CMP0114 NEW) cmake_policy(SET CMP0114 NEW)
set(BZIP2_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/bzip2/src/bzip2) set(BZIP2_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/bzip2/src/bzip2)
# Specify SOURCE_DIR will cause some errors
ExternalProject_Add(bzip2 ExternalProject_Add(bzip2
GIT_REPOSITORY https://android.googlesource.com/platform/external/bzip2 GIT_REPOSITORY https://android.googlesource.com/platform/external/bzip2
GIT_TAG platform-tools-30.0.2 GIT_TAG platform-tools-30.0.2
PREFIX deps/bzip2 PREFIX deps/bzip2
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/bzip2 # SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/bzip2
CONFIGURE_COMMAND mkdir -p ${BZIP2_BUILD_DIR} && git archive --format tar HEAD | tar -C ${BZIP2_BUILD_DIR} -x CONFIGURE_COMMAND mkdir -p ${BZIP2_BUILD_DIR} && git archive --format tar HEAD | tar -C ${BZIP2_BUILD_DIR} -x
BUILD_IN_SOURCE ON BUILD_IN_SOURCE ON
BUILD_COMMAND make -C ${BZIP2_BUILD_DIR} -j4 CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} libbz2.a BUILD_COMMAND make -C ${BZIP2_BUILD_DIR} -j4 CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} libbz2.a
@ -279,6 +280,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/mifare4.c ${PM3_ROOT}/client/src/mifare/mifare4.c
${PM3_ROOT}/client/src/mifare/mifaredefault.c ${PM3_ROOT}/client/src/mifare/mifaredefault.c
${PM3_ROOT}/client/src/mifare/mifarehost.c ${PM3_ROOT}/client/src/mifare/mifarehost.c
${PM3_ROOT}/client/src/mifare/gen4.c
${PM3_ROOT}/client/src/nfc/ndef.c ${PM3_ROOT}/client/src/nfc/ndef.c
${PM3_ROOT}/client/src/mifare/lrpcrypto.c ${PM3_ROOT}/client/src/mifare/lrpcrypto.c
${PM3_ROOT}/client/src/mifare/desfirecrypto.c ${PM3_ROOT}/client/src/mifare/desfirecrypto.c
@ -286,6 +288,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/mifare/desfirecore.c ${PM3_ROOT}/client/src/mifare/desfirecore.c
${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/desfiretest.c
${PM3_ROOT}/client/src/mifare/gallaghercore.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c
${PM3_ROOT}/client/src/uart/ringbuffer.c
${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_posix.c
${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/uart/uart_win32.c
${PM3_ROOT}/client/src/ui/overlays.ui ${PM3_ROOT}/client/src/ui/overlays.ui
@ -656,6 +659,8 @@ if (MINGW)
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}") set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
# link Winsock2
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
endif (MINGW) endif (MINGW)
# GCC 10 has issues with false positives on stringop-overflow, # GCC 10 has issues with false positives on stringop-overflow,

View file

@ -1,3 +1,4 @@
#!/bin/bash #!/bin/bash
gcc -o test test.c -I../../include -lpm3rrg_rdv4 -L../build -lpthread gcc -o test test.c -I../../include -lpm3rrg_rdv4 -L../build -lpthread
gcc -o test_grab test_grab.c -I../../include -lpm3rrg_rdv4 -L../build -lpthread

View file

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
LD_LIBRARY_PATH=../build ./test LD_LIBRARY_PATH=../build ./test /dev/ttyACM0

View file

@ -0,0 +1,3 @@
#!/bin/bash
LD_LIBRARY_PATH=../build ./test_grab /dev/ttyACM0

View file

@ -1,8 +1,14 @@
#include <stdio.h>
#include <stdlib.h>
#include "pm3.h" #include "pm3.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s <port>\n", argv[0]);
exit(-1);
}
pm3 *p; pm3 *p;
p = pm3_open("/dev/ttyACM0"); p = pm3_open(argv[1]);
pm3_console(p, "hw status"); pm3_console(p, "hw status");
pm3_close(p); pm3_close(p);
} }

View file

@ -0,0 +1,74 @@
#include "pm3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int pipefd[2];
char buf[8196 + 1];
size_t n;
if (argc < 2) {
printf("Usage: %s <port>\n", argv[0]);
exit(-1);
}
if (pipe(pipefd) == -1) {
exit(-1);
}
int pid = fork();
if (pid == -1) {
perror("fork");
exit(-1);
}
// child
if (pid == 0) {
printf("[INFO] inside child\n");
// Redirect stdout to the write end of the pipe
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]); // Child: close read end of the pipe
close(pipefd[1]); // Close original write end
pm3 *p;
p = pm3_open(argv[1]);
// Execute the command
pm3_console(p, "hw status");
pm3_close(p);
_exit(-1);
} else {
printf("[INFO] inside parent\n");
// Parent: close write end of the pipe
close(pipefd[1]);
// Read from the pipe
while (1) {
n = read(pipefd[0], buf, sizeof(buf));
if (n == -1) {
continue;
}
if (n == 0) {
break;
} else {
// null termination
buf[n] = 0;
if (strstr(buf, "ERROR") != NULL) {
printf("%s", buf);
}
if (strstr(buf, "Unique ID") != NULL) {
printf("%s", buf);
}
}
}
// Close read end
close(pipefd[0]);
}
}

View file

@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
copyright = '' copyright = ''
author = "Michael Micsen" author = "Michael Micsen"
version = 'v0.0.1' version = 'v0.0.2'
desc = [[ desc = [[
Perform simulation of Mifare credentials with HID encoding Perform simulation of Mifare credentials with HID encoding
This script only supports: H10301 This script only supports: H10301
@ -17,12 +17,12 @@ example = [[
script run hf_mf_sim_hid.lua -f 1 -c 10000 script run hf_mf_sim_hid.lua -f 1 -c 10000
]] ]]
usage = [[ usage = [[
script run hf_mf_sim_hid.lua -f facility -c card_number script run hf_mf_sim_hid.lua -f <dec> -c <dec>
]] ]]
arguments = [[ arguments = [[
-h : this help -h : this help
-f : facility id -f : facility code
-c : starting card id -c : card number
]] ]]
local DEBUG = true local DEBUG = true
--local bxor = bit32.bxor --local bxor = bit32.bxor
@ -126,7 +126,6 @@ local function cardHex(i, f)
sentinel = lshift(1, 26) sentinel = lshift(1, 26)
bits = bor(bits, sentinel) bits = bor(bits, sentinel)
return ('%08x'):format(bits) return ('%08x'):format(bits)
end end
--- ---
@ -146,15 +145,14 @@ local function main(args)
if o == 'h' then return help() end if o == 'h' then return help() end
if o == 'f' then if o == 'f' then
if isempty(a) then if isempty(a) then
print('You did not supply a facility code, using 0') print('Defaulting to facility code 0')
facility = 0 facility = 0
else else
facility = a facility = a
end end
end end
if o == 'c' then if o == 'c' then
print(a) if isempty(a) then return oops('You must supply a card number') end
if isempty(a) then return oops('You must supply the flag -c (card number)1') end
cardnum = a cardnum = a
end end
end end
@ -162,23 +160,27 @@ local function main(args)
--Due to my earlier complaints about how this specific getopt library --Due to my earlier complaints about how this specific getopt library
--works, specifying ':' does not enforce supplying a value, thus we --works, specifying ':' does not enforce supplying a value, thus we
--need to do these checks all over again. --need to do these checks all over again.
if isempty(cardnum) then return oops('You must supply the flag -c (card number)2') end if isempty(cardnum) then return oops('You must supply a card number') end
--If the facility ID is non specified, ensure we code it as zero --If the facility ID is non specified, ensure we code it as zero
if isempty(facility) then if isempty(facility) then
print('Using 0 for the facility code as -f was not supplied') print('Defaulting to facility code 0')
facility = 0 facility = 0
end end
-- Write the MAD to read for a Mifare HID credential -- Write the MAD to read for a Mifare HID credential
core.console('hf mf esetblk -b 1 -d 1B014D48000000000000000000000000') core.console('hf mf esetblk --blk 1 -d 1B014D48000000000000000000000000')
core.console('hf mf esetblk -b 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A') core.console('hf mf esetblk --blk 3 -d A0A1A2A3A4A5787788C189ECA97F8C2A')
--Write the sector trailer for the credential sector --Write the sector trailer for the credential sector
core.console('hf mf esetblk -b 7 -d 484944204953787788AA204752454154') core.console('hf mf esetblk --blk 7 -d 484944204953787788AA204752454154')
local cardh = cardHex(cardnum, facility) local cardh = cardHex(cardnum, facility)
print('Hex')
print(cardh)
core.console( ('hf mf esetblk -b 5 -d 020000000000000000000000%s'):format(cardh) )
print('Facility Code... ' .. facility)
print('Card number..... ' .. cardnum)
print('Hex............. ' .. cardh)
print('')
core.console( ('hf mf esetblk --blk 5 -d 020000000000000000000000%s'):format(cardh) )
core.console('hf mf sim --1k -i') core.console('hf mf sim --1k -i')
end end

View file

@ -87,12 +87,6 @@ local function ExitMsg(msg)
print() print()
end end
local function writedumpfile(infile)
t = infile:read('*all')
len = string.len(t)
local len,hex = bin.unpack(('H%d'):format(len),t)
return hex
end
-- blocks with data -- blocks with data
-- there are two dataareas, in block 8 or block 36, ( 1==8 , -- there are two dataareas, in block 8 or block 36, ( 1==8 ,
-- checksum type = 0, 1, 2, 3 -- checksum type = 0, 1, 2, 3

View file

@ -82,16 +82,16 @@ local function main(args)
sd = sd or 2000 sd = sd or 2000
ed = ed or 2100 ed = ed or 2100
if #password ~= 8 then if password ~= '' and #password ~= 8 then
password = '' return oops('password must be 4 hex bytes')
end end
if #wr_value ~= 8 then if #wr_value ~= 8 then
wr_value = 'FFFFFFFF' return oops('write value must be 4 hex bytes')
end end
if #rd_value ~= 8 then if #rd_value ~= 8 then
rd_value = 'FFFFFFFF' return oops('read value must be 4 hex bytes')
end end
if sd > ed then if sd > ed then
@ -114,7 +114,7 @@ local function main(args)
local set_tearoff_delay = 'hw tearoff --delay %d' local set_tearoff_delay = 'hw tearoff --delay %d'
local enable_tearoff = 'hw tearoff --on' local enable_tearoff = 'hw tearoff --on'
local wr_template = 'lf em 4x05_write %s %s %s' local wr_template = 'lf em 4x05 write --addr %s --data %s --pwd %s'
-- init addr to value -- init addr to value
core.console(wr_template:format(addr, wr_value, password)) core.console(wr_template:format(addr, wr_value, password))

View file

@ -49,7 +49,7 @@
}, },
{ {
"AID": "F21190", "AID": "F21190",
"Vendor": "Metropolitan Transportation Commission", "Vendor": "Metropolitan Transportation Commission / Cubic",
"Country": "US", "Country": "US",
"Name": "Clipper Card", "Name": "Clipper Card",
"Description": "", "Description": "",
@ -81,7 +81,7 @@
}, },
{ {
"AID": "784000", "AID": "784000",
"Vendor": "NO1", "Vendor": "NOL",
"Country": "UAE", "Country": "UAE",
"Name": "Nol Card/Dubai", "Name": "Nol Card/Dubai",
"Description": "Nol Card/Dubai", "Description": "Nol Card/Dubai",
@ -121,7 +121,7 @@
}, },
{ {
"AID": "F21030", "AID": "F21030",
"Vendor": "ORCA Card", "Vendor": "ORCA (VUX/ERG)",
"Country": "", "Country": "",
"Name": "ORCA Card", "Name": "ORCA Card",
"Description": "(FIDs 02: Trip History; 04: current balance)", "Description": "(FIDs 02: Trip History; 04: current balance)",
@ -383,5 +383,157 @@
"Name": "Disney MagicBand", "Name": "Disney MagicBand",
"Description": "AID found on MagicBand desfire cards", "Description": "AID found on MagicBand desfire cards",
"Type": "payment system" "Type": "payment system"
},
{
"AID": "F21100",
"Vendor": "MyKI",
"Country": "AUS",
"Name": "Myki",
"Description": "AID found on Myki ticket cards",
"Type": "transport"
},
{
"AID": "F210F0",
"Vendor": "MyKI",
"Country": "AUS",
"Name": "Myki",
"Description": "AID found on Myki ticket cards",
"Type": "transport"
},
{
"AID": "F206B0",
"Vendor": "ACS",
"Country": "AUS",
"Name": "Metrocard / ACS",
"Description": "",
"Type": "transport"
},
{
"AID": "F21050",
"Vendor": "INIT",
"Country": "NZ",
"Name": "Metrocard / Christchurch",
"Description": "",
"Type": "transport"
},
{
"AID": "F21150",
"Vendor": "HAGUESS",
"Country": "CZ",
"Name": "Lítačka / Prague",
"Description": "",
"Type": "transport"
},
{
"AID": "F21360",
"Vendor": "INIT",
"Country": "CZ",
"Name": "HOLO",
"Description": "",
"Type": "transport"
},
{
"AID": "F21381",
"Vendor": "Cubic",
"Country": "US",
"Name": "Ventra",
"Description": "",
"Type": "transport"
},
{
"AID": "F213A0",
"Vendor": "INIT",
"Country": "US",
"Name": "WAVE / Rhode Island",
"Description": "",
"Type": "transport"
},
{
"AID": "F210E0",
"Vendor": "Hop Fastpass",
"Country": "",
"Name": "Hop Fastpass",
"Description": "",
"Type": "transport"
},
{
"AID": "EF2011",
"Vendor": "HSL",
"Country": "FI",
"Name": "HSL / Helsinki",
"Description": "",
"Type": "transport"
},
{
"AID": "A00216",
"Vendor": "ITSO",
"Country": "",
"Name": "ITSO",
"Description": "",
"Type": "transport"
},
{
"AID": "554000",
"Vendor": "AT HOP",
"Country": "",
"Name": "AT HOP",
"Description": "",
"Type": "transport"
},
{
"AID": "534531",
"Vendor": "OPAL",
"Country": "AUS",
"Name": "OPAL",
"Description": "",
"Type": "transport"
},
{
"AID": "2211AF",
"Vendor": "Leap",
"Country": "",
"Name": "Leap",
"Description": "",
"Type": "transport"
},
{
"AID": "015342",
"Vendor": "BEM",
"Country": "TH",
"Name": "BEM / Bangkok",
"Description": "",
"Type": "transport"
},
{
"AID": "012242",
"Vendor": "Istanbulkart",
"Country": "TR",
"Name": "Istanbulkart / Istanbul",
"Description": "",
"Type": "transport"
},
{
"AID": "010000",
"Vendor": "Madrid Public Transit Card",
"Country": "ES",
"Name": "Madrid Public Transit Card",
"Description": "",
"Type": "transport"
},
{
"AID": "000001",
"Vendor": "Invalid / reserved",
"Country": "",
"Name": "Invalid / reserved",
"Description": "used by Compass DESFire and Breeze DESFire",
"Type": "transport"
},
{
"AID": "FFFFFF",
"Vendor": "Reserved for future use",
"Country": "",
"Name": "Reserved for future use",
"Description": "used by AT HOP, Nol, ORCA",
"Type": "transport"
} }
] ]

View file

@ -2940,7 +2940,7 @@
"system_integrator": "A.I.I." "system_integrator": "A.I.I."
}, },
{ {
"application": "Multi-Modal Transit", "application": "Multi-Modal Transit (Vix/ERG)",
"company": "ERG Transit Systems", "company": "ERG Transit Systems",
"mad": "0x2103", "mad": "0x2103",
"service_provider": "ERG Transit Systems", "service_provider": "ERG Transit Systems",
@ -2953,6 +2953,13 @@
"service_provider": "ERG Transit Systems", "service_provider": "ERG Transit Systems",
"system_integrator": "ERG Transit Systems" "system_integrator": "ERG Transit Systems"
}, },
{
"application": "Transit (Metrocard / Christchurch)",
"company": "INIT Transit Systems",
"mad": "0x2105",
"service_provider": "INIT Transit Systems",
"system_integrator": "INIT Transit Systems"
},
{ {
"application": "Mass Transportation Ticketing", "application": "Mass Transportation Ticketing",
"company": "Omnifare", "company": "Omnifare",
@ -2995,6 +3002,13 @@
"service_provider": "Emcard", "service_provider": "Emcard",
"system_integrator": "Emtest" "system_integrator": "Emtest"
}, },
{
"application": "Integrated multi-modal transport ticketing system",
"company": "HOP Fastpass",
"mad": "0x210E",
"service_provider": "HOP Fastpass",
"system_integrator": "HOP Fastpass"
},
{ {
"application": "Integrated multi-modal transport ticketing system", "application": "Integrated multi-modal transport ticketing system",
"company": "Keane Australia PTY Limited", "company": "Keane Australia PTY Limited",
@ -3038,7 +3052,7 @@
"system_integrator": "T-Systems GEI" "system_integrator": "T-Systems GEI"
}, },
{ {
"application": "Transportation ticket", "application": "Transportation ticket (Lítačka)",
"company": "Haguess s.r.o.", "company": "Haguess s.r.o.",
"mad": "0x2115", "mad": "0x2115",
"service_provider": "HAGUESS, a.s.", "service_provider": "HAGUESS, a.s.",
@ -3135,6 +3149,35 @@
"service_provider": "RTD", "service_provider": "RTD",
"system_integrator": "ACS" "system_integrator": "ACS"
}, },
{
"application": "Bus and rail fare collection (HOLO)",
"company": "INIT",
"mad": "0x2136",
"service_provider": "INIT",
"system_integrator": "INIT"
},
{
"application": "Bus and rail fare collection (Ventra)",
"company": "Cubic",
"mad": "0x2138",
"service_provider": "Cubic",
"system_integrator": "Cubic"
},
{
"application": "Bus and rail fare collection (Clipper)",
"company": "Cubic",
"mad": "0x2139",
"service_provider": "Cubic",
"system_integrator": "Cubic"
},
{
"application": "Bus and rail fare collection (WAVE)",
"company": "INIT Rhode Island",
"mad": "0x213A",
"service_provider": "INIT Rhode Island",
"system_integrator": "INIT Rhode Island"
},
{ {
"application": "Bus services with extension to rail and taxi", "application": "Bus services with extension to rail and taxi",
"company": "Questek Marketing", "company": "Questek Marketing",
@ -13621,5 +13664,12 @@
"mad": "0xF001", "mad": "0xF001",
"service_provider": "Tech ID", "service_provider": "Tech ID",
"system_integrator": "Tech ID" "system_integrator": "Tech ID"
},
{
"application": "Miscellaneous applications",
"company": "Reserved For future Use",
"mad": "0xFFFF",
"service_provider": "RFU",
"system_integrator": "RFU"
} }
] ]

BIN
client/resources/sim014.bin Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
8b754191cec19a8172ff77443eee67490f61c53161af2e831ff4e8c7909b788802f5c0b68cecdc5decabe7852479740a0122832803af26b68beab814ced543b8 *client/resources/sim014.bin

View file

@ -34,6 +34,7 @@ const char *getAtrInfo(const char *atr_str);
// atr_t array is expected to be NULL terminated // atr_t array is expected to be NULL terminated
const static atr_t AtrTable[] = { const static atr_t AtrTable[] = {
{ "3BDF18FFC080B1FE751F033078464646462026204963656D616E1D", "Cardhelper by 0xFFFF and Iceman" }, { "3BDF18FFC080B1FE751F033078464646462026204963656D616E1D", "Cardhelper by 0xFFFF and Iceman" },
{ "3B90969181B1FE551FC7D4", "IClass SE Processor (Other) https://www.hidglobal.com/products/embedded-modules/iclass-se/sio-processor"},
{ "3B..............0031B8640000000073......829000", "MultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 3" }, { "3B..............0031B8640000000073......829000", "MultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 3" },
{ "3B..............0031B8640000000073......829000..", "MultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 4" }, { "3B..............0031B8640000000073......829000..", "MultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 4" },
{ "3B........0031B864........73......829000", "IDClassic IAS (old name: IAS TPC) IAS ECC Type 1\nMultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 1" }, { "3B........0031B864........73......829000", "IDClassic IAS (old name: IAS TPC) IAS ECC Type 1\nMultiApp ID IAS ECC 72K CC (with IAS XL / IAS ECC Applet) IAS ECC Type 1" },
@ -362,6 +363,7 @@ const static atr_t AtrTable[] = {
{ "3B3C110042AF20A32007002283829000", "Orange Mobicarte (SIM card old generation)" }, { "3B3C110042AF20A32007002283829000", "Orange Mobicarte (SIM card old generation)" },
{ "3B3C110044AF11F7200504FB83819000", "itineris (Old French Mobile Operator SIM card) (Telecommunication)" }, { "3B3C110044AF11F7200504FB83819000", "itineris (Old French Mobile Operator SIM card) (Telecommunication)" },
{ "3B3C9400423111A21202095183809000", "Omnitel IT 16K GSM SIM card" }, { "3B3C9400423111A21202095183809000", "Omnitel IT 16K GSM SIM card" },
{ "3B3C9400443111F000002CAE83839000", "Movistar Spain (Telecommunication)" },
{ "3B3C94004B3125A21013144783839000", "GSM SFR" }, { "3B3C94004B3125A21013144783839000", "GSM SFR" },
{ "3B3C94004C3125A7201B001583839000", "GSM-SIM (900MHz) card of the carrier vodafone for their cellular\nnetwork (phase 2+ with 3V)" }, { "3B3C94004C3125A7201B001583839000", "GSM-SIM (900MHz) card of the carrier vodafone for their cellular\nnetwork (phase 2+ with 3V)" },
{ "3B3C9400633112F00000464083839000", "Old russian 'beeline' sim" }, { "3B3C9400633112F00000464083839000", "Old russian 'beeline' sim" },
@ -425,6 +427,7 @@ const static atr_t AtrTable[] = {
{ "3B5F9600805A2C1100101000FFFFFFFF829000", "Calypso (Transport)" }, { "3B5F9600805A2C1100101000FFFFFFFF829000", "Calypso (Transport)" },
{ "3B5F9600805A3F0608140101C546DEDC829000", "Navegante(r) Personalizado (Lisbon public transportation card) (Transport)\nhttps://www.navegante.pt/viajar/cartoes" }, { "3B5F9600805A3F0608140101C546DEDC829000", "Navegante(r) Personalizado (Lisbon public transportation card) (Transport)\nhttps://www.navegante.pt/viajar/cartoes" },
{ "3B5F9600805A3F0608140101C546EBDC829000", "Multi-Transport Pass (Navegante) (Metro, Bus, Electric, Boat) Carris Metropolitano, PT (Transport)\nhttps://www.navegante.pt/" }, { "3B5F9600805A3F0608140101C546EBDC829000", "Multi-Transport Pass (Navegante) (Metro, Bus, Electric, Boat) Carris Metropolitano, PT (Transport)\nhttps://www.navegante.pt/" },
{ "3B5F9600805A3F0608201223C4325FDE829000", "Montreal metropolitan area and Quebec city area OPUS card (Transport)\nhttps://www.carteopus.info/" },
{ "3B600000", "Meano (Bank)" }, { "3B600000", "Meano (Bank)" },
{ "3B61000080", "blank A40CR card (JavaCard)" }, { "3B61000080", "blank A40CR card (JavaCard)" },
{ "3B630000364180", "Schlumberger Payflex 4k User" }, { "3B630000364180", "Schlumberger Payflex 4k User" },
@ -1189,6 +1192,7 @@ const static atr_t AtrTable[] = {
{ "3B6F0000805A28130210122B75021B8A829000", "KorriGo, smart transport card in France region Brittany (Transport)\nhttps://www.ter.sncf.com/bretagne/offres/carte-korrigo" }, { "3B6F0000805A28130210122B75021B8A829000", "KorriGo, smart transport card in France region Brittany (Transport)\nhttps://www.ter.sncf.com/bretagne/offres/carte-korrigo" },
{ "3B6F0000805A28130210122B7503FB01829000", "origo (France) (Transport)\nhttps://www.breizhgo.bzh/se-deplacer-en-bretagne/KorriGo" }, { "3B6F0000805A28130210122B7503FB01829000", "origo (France) (Transport)\nhttps://www.breizhgo.bzh/se-deplacer-en-bretagne/KorriGo" },
{ "3B6F0000805A28130210122B750C7E79829000", "Transportation card delivered by STAR (Transportation service from the city of Rennes, France) (Transport)\nhttps://www.star.fr/titres-et-tarifs/carte-korrigo/" }, { "3B6F0000805A28130210122B750C7E79829000", "Transportation card delivered by STAR (Transportation service from the city of Rennes, France) (Transport)\nhttps://www.star.fr/titres-et-tarifs/carte-korrigo/" },
{ "3B6F0000805A28130210122B750DD382829000", "ZOU! for Region Sud (Transport)\nhttps://zou.maregionsud.fr/ma-carte-zou/" },
{ "3B6F0000805A28130210122B9292E642829000", "Transport card in cote d'or France (mobigo)" }, { "3B6F0000805A28130210122B9292E642829000", "Transport card in cote d'or France (mobigo)" },
{ "3B6F0000805A28130210122B9292E829829000", "French transport card of the city of Dijon and Cote d'or department. (Transport)\nhttps://www.viamobigo.fr/fr/acheter-mes-titres-de-transport-mobigo-en-cote-dor/176" }, { "3B6F0000805A28130210122B9292E829829000", "French transport card of the city of Dijon and Cote d'or department. (Transport)\nhttps://www.viamobigo.fr/fr/acheter-mes-titres-de-transport-mobigo-en-cote-dor/176" },
{ "3B6F0000805A28130210122B92D663FC829000", "Card 'Korrigo' region Bretagne, France, Bibus Brest Metropole public transport (Transport)\nhttps://fr.wikipedia.org/wiki/KorriGo" }, { "3B6F0000805A28130210122B92D663FC829000", "Card 'Korrigo' region Bretagne, France, Bibus Brest Metropole public transport (Transport)\nhttps://fr.wikipedia.org/wiki/KorriGo" },
@ -1227,6 +1231,7 @@ const static atr_t AtrTable[] = {
{ "3B6F0000805A2D06081010027835EDCE829000", "Lisbon Transportation SmartCard (Transport)" }, { "3B6F0000805A2D06081010027835EDCE829000", "Lisbon Transportation SmartCard (Transport)" },
{ "3B6F0000805A2D06081010027848BBCC829000", "Lisbon Metro Monthly Student Pass (Transport)\nhttps://www.metrolisboa.pt/" }, { "3B6F0000805A2D06081010027848BBCC829000", "Lisbon Metro Monthly Student Pass (Transport)\nhttps://www.metrolisboa.pt/" },
{ "3B6F0000805A2D0608101005935C42FB829000", "Comboios de Portugal Transit Card (Transport)\nhttps://www.cp.pt/passageiros/pt/consultar-horarios/precos/cartao-cp" }, { "3B6F0000805A2D0608101005935C42FB829000", "Comboios de Portugal Transit Card (Transport)\nhttps://www.cp.pt/passageiros/pt/consultar-horarios/precos/cartao-cp" },
{ "3B6F0000805A2E130200010104EF8342829000", "Oura Auvergne-Rhone-Alpes (Transport)\nhttps://www.oura.com" },
{ "3B6F0000805A3407061500017917A7E2829000", "Rav-Kav multi-line travel ticket used in the public transportation system in Israel (Transport)\nhttps://www.gov.il/en/departments/guides/multi_line_card" }, { "3B6F0000805A3407061500017917A7E2829000", "Rav-Kav multi-line travel ticket used in the public transportation system in Israel (Transport)\nhttps://www.gov.il/en/departments/guides/multi_line_card" },
{ "3B6F0000805A340706150001792A4B5C829000", "Rav Kav Transit Payment Card (Israel) (Transport)\nhttps://ravkavonline.co.il/" }, { "3B6F0000805A340706150001792A4B5C829000", "Rav Kav Transit Payment Card (Israel) (Transport)\nhttps://ravkavonline.co.il/" },
{ "3B6F0000805A3B0706150101793E797B829000", "Rav Kav (Transport)\nhttp://alhakav.mot.gov.il/he/rav-kav" }, { "3B6F0000805A3B0706150101793E797B829000", "Rav Kav (Transport)\nhttp://alhakav.mot.gov.il/he/rav-kav" },
@ -1468,7 +1473,7 @@ const static atr_t AtrTable[] = {
{ "3B7F..0000006A4345524553022C3402..039000", "Ceres ST v2" }, { "3B7F..0000006A4345524553022C3402..039000", "Ceres ST v2" },
{ "3B7F..0000006A4345524553022C3403..039000", "Ceres ST v3" }, { "3B7F..0000006A4345524553022C3403..039000", "Ceres ST v3" },
{ "3B7F..00008031..65B000000000......8290..", "MultiApp V2.1 (with IAS XL / IAS ECC and IAS Classic Applet V3) [MultiApp V2.1 Type 2]" }, { "3B7F..00008031..65B000000000......8290..", "MultiApp V2.1 (with IAS XL / IAS ECC and IAS Classic Applet V3) [MultiApp V2.1 Type 2]" },
{ "3B7F..000080318065B0........120FFE829000", "IDPrime MD 8840, 3840, 3810, 840 and 830 Cards T=0" }, { "3B7F..000080318065B0........120FFE829000", "IDPrime MD 8840, 3840, 3810, 840 and 830 Cards T=0\nIDPrime 930 (JavaCard)" },
{ "3B7F0100FE58434F53763235312863295046424D", "XCOS is an Experimental Card Operating System for Atmel based smartcards (Funcard, etc..) (Other)\nhttp://runningserver.com/?page=runningserver.content.download.xcos" }, { "3B7F0100FE58434F53763235312863295046424D", "XCOS is an Experimental Card Operating System for Atmel based smartcards (Funcard, etc..) (Other)\nhttp://runningserver.com/?page=runningserver.content.download.xcos" },
{ "3B7F04000080318071906754454D44412E309000", "public key (PKI)" }, { "3B7F04000080318071906754454D44412E309000", "public key (PKI)" },
{ "3B7F1100000031C053CAC4016452D90400829000", "DoD CAC, Oberthur CosmopolIC 32K V4" }, { "3B7F1100000031C053CAC4016452D90400829000", "DoD CAC, Oberthur CosmopolIC 32K V4" },
@ -1604,6 +1609,7 @@ const static atr_t AtrTable[] = {
{ "3B7F96000080318065B085050011120FFF829000", "LuxTrust card (Luxembourg qualified electronic signature / authentication system) (Other)\nhttps://www.luxtrust.com/en/professionals/smartcard" }, { "3B7F96000080318065B085050011120FFF829000", "LuxTrust card (Luxembourg qualified electronic signature / authentication system) (Other)\nhttps://www.luxtrust.com/en/professionals/smartcard" },
{ "3B7F96000080318065B0855956FB120268829000", "qualified certificate (eID)\nhttps://www.elektronicznypodpis.pl/en/offer/qualified-certificates/" }, { "3B7F96000080318065B0855956FB120268829000", "qualified certificate (eID)\nhttps://www.elektronicznypodpis.pl/en/offer/qualified-certificates/" },
{ "3B7F96000080318065B0855956FB1202C1829000", "Gemalto USB (eID)" }, { "3B7F96000080318065B0855956FB1202C1829000", "Gemalto USB (eID)" },
{ "3B7F96000080318065B0855956FB120FFE829000", "Thales (Gemalto) IDPrime 941 (PKI)\nhttps://cpl.thalesgroup.com/de/access-management/idprime-md-pki-smart-cards\nThales SafeNet IDPrime 940B (PKI)\nhttps://cpl.thalesgroup.com/resources/access-management/idprime-940-product-brief" },
{ "3B7F96000080318065B0855956FB12FFFE829000", "IDCORE 3140 (JavaCard)" }, { "3B7F96000080318065B0855956FB12FFFE829000", "IDCORE 3140 (JavaCard)" },
{ "3B7F9600008031B865B0850300EF1200F6829000", "Finnish identity card (eID)\nhttp://vrk.fi/en/citizen-certificate" }, { "3B7F9600008031B865B0850300EF1200F6829000", "Finnish identity card (eID)\nhttp://vrk.fi/en/citizen-certificate" },
{ "3B7F9600008031B865B08504021B1200F6829000", "Finnish ID-card v5.0(?) (eID)\nhttps://dvv.fi/en/fineid-specifications" }, { "3B7F9600008031B865B08504021B1200F6829000", "Finnish ID-card v5.0(?) (eID)\nhttps://dvv.fi/en/fineid-specifications" },
@ -1705,6 +1711,7 @@ const static atr_t AtrTable[] = {
{ "3B8680014B4F4E41141109", "Mastercard paypass enabled credit card" }, { "3B8680014B4F4E41141109", "Mastercard paypass enabled credit card" },
{ "3B8680015741524930310B", "Gusto Karta (Bank)\nhttps://www.gustokarta.cz" }, { "3B8680015741524930310B", "Gusto Karta (Bank)\nhttps://www.gustokarta.cz" },
{ "3B86800157575061737336", "WWPass Passkey (eID)\nhttps://www.wwpass.com/passkey" }, { "3B86800157575061737336", "WWPass Passkey (eID)\nhttps://www.wwpass.com/passkey" },
{ "3B868001801434373000A0", "Malta eID Identity Card (eID)\nhttps://www.identitymalta.com/" },
{ "3B8680018031C15211182C", "IDEMIA Cosmo V8.0 with a PIV applet (contactless) (PKI)" }, { "3B8680018031C15211182C", "IDEMIA Cosmo V8.0 with a PIV applet (contactless) (PKI)" },
{ "3B8680018031C152411A7E", "IDEMIA Cosmo V8.1 with a PIV applet (contactless) (PKI)" }, { "3B8680018031C152411A7E", "IDEMIA Cosmo V8.1 with a PIV applet (contactless) (PKI)" },
{ "3B86800180540410010FC9", "Nickel.eu prepaid account (Bank)\nhttps://nickel.eu" }, { "3B86800180540410010FC9", "Nickel.eu prepaid account (Bank)\nhttps://nickel.eu" },
@ -2006,6 +2013,7 @@ const static atr_t AtrTable[] = {
{ "3B8C8001505CF5A94530AAAA017781D708", "Indonesia ektp (eID)" }, { "3B8C8001505CF5A94530AAAA017781D708", "Indonesia ektp (eID)" },
{ "3B8C800150605F2EFA00000000778191D1", "Residence Permit (Switzerland) (eID)" }, { "3B8C800150605F2EFA00000000778191D1", "Residence Permit (Switzerland) (eID)" },
{ "3B8C80015064E65B000000000000818085", "Chicago CTA Ventra Transit card\nhttps://www.ventrachicago.com/" }, { "3B8C80015064E65B000000000000818085", "Chicago CTA Ventra Transit card\nhttps://www.ventrachicago.com/" },
{ "3B8C80015068DDA5B11C00001177818582", "EZ-Link Card (issued by Land Transport Authority Singapore) (Transport)\nhttps://www.ezlink.com.sg/ez-link-faqs/ez-link-card/" },
{ "3B8C800150710CF3C800000000B37171A8", "MOBIB CARD BELGIUM (Transport)" }, { "3B8C800150710CF3C800000000B37171A8", "MOBIB CARD BELGIUM (Transport)" },
{ "3B8C800150773B2DBD0000001100818594", "Texas Instruments Dynamic NFC Interface Transponder (RF430CL330H)" }, { "3B8C800150773B2DBD0000001100818594", "Texas Instruments Dynamic NFC Interface Transponder (RF430CL330H)" },
{ "3B8C800150784B2CCB00000000B371713A", "... (Transport)\nhttps://www.portalviva.pt/" }, { "3B8C800150784B2CCB00000000B371713A", "... (Transport)\nhttps://www.portalviva.pt/" },
@ -2135,6 +2143,7 @@ const static atr_t AtrTable[] = {
{ "3B8F80010031B96409377213738401E0000000AB", "National Identity Card of Slovakia (NFC interface) (eID)\nhttps://en.wikipedia.org/wiki/Slovak_identity_card" }, { "3B8F80010031B96409377213738401E0000000AB", "National Identity Card of Slovakia (NFC interface) (eID)\nhttps://en.wikipedia.org/wiki/Slovak_identity_card" },
{ "3B8F80010031C173C800106457494943009000B5", "ICC Solutions Card for Certification (Other)\nhttps://www.iccsolutions.com/" }, { "3B8F80010031C173C800106457494943009000B5", "ICC Solutions Card for Certification (Other)\nhttps://www.iccsolutions.com/" },
{ "3B8F80010031C173C8211064414D31300790008A", "master card (Bank)" }, { "3B8F80010031C173C8211064414D31300790008A", "master card (Bank)" },
{ "3B8F80010031C173C8211064414D313307900089", "CheBanca! nexi debit card (Bank)\nhttps://www.chebanca.it/" },
{ "3B8F80010031C173C8211064414D31370790008D", "AirPlus International Mastercard (Bank)\nhttps://www.airplus.com/" }, { "3B8F80010031C173C8211064414D31370790008D", "AirPlus International Mastercard (Bank)\nhttps://www.airplus.com/" },
{ "3B8F80010031C173C8211064414D333007900088", "ING-VISA-Card (Bank)\nhttps://www.ing.de/girokonto/karten-bargeld/" }, { "3B8F80010031C173C8211064414D333007900088", "ING-VISA-Card (Bank)\nhttps://www.ing.de/girokonto/karten-bargeld/" },
{ "3B8F80010031C173C8211064414D333107900089", "NAB VISA Debit (Bank)\nhttps://www.nab.com.au/" }, { "3B8F80010031C173C8211064414D333107900089", "NAB VISA Debit (Bank)\nhttps://www.nab.com.au/" },
@ -2276,7 +2285,7 @@ const static atr_t AtrTable[] = {
{ "3B8F8001804F0CA0000003060E....00000000..", "Contact (7816-10) Extended I2C (as per PCSC std part3)" }, { "3B8F8001804F0CA0000003060E....00000000..", "Contact (7816-10) Extended I2C (as per PCSC std part3)" },
{ "3B8F8001804F0CA0000003060F....00000000..", "Contact (7816-10) 2WBP (as per PCSC std part3)" }, { "3B8F8001804F0CA0000003060F....00000000..", "Contact (7816-10) 2WBP (as per PCSC std part3)" },
{ "3B8F8001804F0CA00000030610....00000000..", "RFID - FeliCa compatible (as per PCSC std part3)\nContact (7816-10) 3WBP (as per PCSC std part3)" }, { "3B8F8001804F0CA00000030610....00000000..", "RFID - FeliCa compatible (as per PCSC std part3)\nContact (7816-10) 3WBP (as per PCSC std part3)" },
{ "3B8F8001804F0CA00000030611003B0000000042", "RFID - FeliCa (generic) (as per PCSC std part3)\nSuica public transit card (Japan IC system)\n(also: Hayakaken, ICOCA, Kitaca, manaca, nimoca, PASMO, PiTaPa, SUGOCA, TOICA)\nhttps://en.wikipedia.org/wiki/Suica\nOctopus, MTR network from Hong Kong, 2014" }, { "3B8F8001804F0CA00000030611003B0000000042", "RFID - FeliCa (generic) (as per PCSC std part3)\nSuica public transit card (Japan IC system)\n(also: Hayakaken, ICOCA, Kitaca, manaca, nimoca, PASMO, PiTaPa, SUGOCA, TOICA)\nhttps://en.wikipedia.org/wiki/Suica\nOctopus, MTR network from Hong Kong, 2014\ne-Amusement card (Other)\nhttps://en.wikipedia.org/wiki/E-Amusement" },
{ "3B8F8001804F0CA00000030640....00000000..", "RFID - Low Frequency < 135 kHz (as per PCSC std part3)" }, { "3B8F8001804F0CA00000030640....00000000..", "RFID - Low Frequency < 135 kHz (as per PCSC std part3)" },
{ "3B8F8001804F0CA0000003064000000000000028", "HID Proximity. Used to access buildings. Reference on the card 'HID0008P'.\nhttp://www.hidglobal.com/product-display/cards-and-credentials/hid-proximity" }, { "3B8F8001804F0CA0000003064000000000000028", "HID Proximity. Used to access buildings. Reference on the card 'HID0008P'.\nhttp://www.hidglobal.com/product-display/cards-and-credentials/hid-proximity" },
{ "3B8F8001804F0CA0001A0000000078", "iclass 16k cl (eID)" }, { "3B8F8001804F0CA0001A0000000078", "iclass 16k cl (eID)" },
@ -2328,7 +2337,6 @@ const static atr_t AtrTable[] = {
{ "3B959640F001130A0A1D", "xcrypt (Pay TV)" }, { "3B959640F001130A0A1D", "xcrypt (Pay TV)" },
{ "3B959640F00F100A096A", "Zain Usim Card (Telecommunication)\nwww.qariya.com" }, { "3B959640F00F100A096A", "Zain Usim Card (Telecommunication)\nwww.qariya.com" },
{ "3B959680B1FE551FC7477261636513", "IClass SE Processor (Other)\nhttps://www.hidglobal.com/products/embedded-modules/iclass-se/sio-processor" }, { "3B959680B1FE551FC7477261636513", "IClass SE Processor (Other)\nhttps://www.hidglobal.com/products/embedded-modules/iclass-se/sio-processor" },
{ "3B90969181B1FE551FC7D4", "IClass SE Processor (Other)\nhttps://www.hidglobal.com/products/embedded-modules/iclass-se/sio-processor"},
{ "3B9596C0F01FC20F100A0A16", "viettel (Telecommunication)" }, { "3B9596C0F01FC20F100A0A16", "viettel (Telecommunication)" },
{ "3B959740F01A160A1941", "SG50 (Samsung Chip) (Telecommunication)" }, { "3B959740F01A160A1941", "SG50 (Samsung Chip) (Telecommunication)" },
{ "3B96004121920000622433339000", "Ukrainian Telecommunications Operator Kyivstar (old simcard) (Telecommunication)\nhttps://kyivstar.ua/uk/mm" }, { "3B96004121920000622433339000", "Ukrainian Telecommunications Operator Kyivstar (old simcard) (Telecommunication)\nhttps://kyivstar.ua/uk/mm" },
@ -2378,6 +2386,7 @@ const static atr_t AtrTable[] = {
{ "3B9A940091010017000126050096", "GSM-SIM T-D1 prepaid (Xtra) (Telecommunication)" }, { "3B9A940091010017000126050096", "GSM-SIM T-D1 prepaid (Xtra) (Telecommunication)" },
{ "3B9A940091010017000126060096", "T D1 GSM card" }, { "3B9A940091010017000126060096", "T D1 GSM card" },
{ "3B9A9400920275931100010202..", "SuperSIM (X-sim)" }, { "3B9A9400920275931100010202..", "SuperSIM (X-sim)" },
{ "3B9A940092029093110001340200", "Orange Spain (Telecommunication)" },
{ "3B9A960092013693170002040300", "GSM-SIM EMT 'Simpel' (prepaid, Estonia)\nhttps://www.emt.ee/web/simpel" }, { "3B9A960092013693170002040300", "GSM-SIM EMT 'Simpel' (prepaid, Estonia)\nhttps://www.emt.ee/web/simpel" },
{ "3B9A960092014893170002120400", "SIM Card C*******r Mobile (Belgium)" }, { "3B9A960092014893170002120400", "SIM Card C*******r Mobile (Belgium)" },
{ "3B9A960092016693170002120400", "GSM SIM Bite.lv prepaid 'Toxic'; 2008" }, { "3B9A960092016693170002120400", "GSM SIM Bite.lv prepaid 'Toxic'; 2008" },
@ -2396,6 +2405,7 @@ const static atr_t AtrTable[] = {
{ "3B9C131181647265616D6372797074000408", "XPlusTV & INXCT Access Card-9 (FIRECrypt)" }, { "3B9C131181647265616D6372797074000408", "XPlusTV & INXCT Access Card-9 (FIRECrypt)" },
{ "3B9C131181647265616D6372797074900599", "FireCrypt, access card 9 (Pay TV)" }, { "3B9C131181647265616D6372797074900599", "FireCrypt, access card 9 (Pay TV)" },
{ "3B9C188121455A43332E333420524556204467", "MS-Protect safecard for access system (eID)" }, { "3B9C188121455A43332E333420524556204467", "MS-Protect safecard for access system (eID)" },
{ "3B9C188121755A43332E333420524556204457", "ZC3.34 (Other)\nhttps://www.zeitcontrol.de/Smart-card-BasicCard-Enhanced-ZC334-SIM-cut" },
{ "3B9C940068868D0A86980256C2000500", "G3 & GSM & Blank SIM card: to be programmed for OpenBTS with pySim-prog (Telecommunication)" }, { "3B9C940068868D0A86980256C2000500", "G3 & GSM & Blank SIM card: to be programmed for OpenBTS with pySim-prog (Telecommunication)" },
{ "3B9C940068868D0C86980245A1000500", "China Mobile (Telecommunication)" }, { "3B9C940068868D0C86980245A1000500", "China Mobile (Telecommunication)" },
{ "3B9C940068868D0C86980256408B0500", "mobiledit (Telecommunication)" }, { "3B9C940068868D0C86980256408B0500", "mobiledit (Telecommunication)" },
@ -2490,6 +2500,7 @@ const static atr_t AtrTable[] = {
{ "3B9E95801FC78031E073FE211B66D00217C71100C0", "3 UK SIM card (Telecommunication)" }, { "3B9E95801FC78031E073FE211B66D00217C71100C0", "3 UK SIM card (Telecommunication)" },
{ "3B9E95801FC78031E073FE211B66D00217F61100F1", "Ziggo SmartCard Television Subscription (Pay TV)" }, { "3B9E95801FC78031E073FE211B66D00217F61100F1", "Ziggo SmartCard Television Subscription (Pay TV)" },
{ "3B9E95801FC78031E073FE211B66D00219151300", "ABS-CBN (Telecommunication)" }, { "3B9E95801FC78031E073FE211B66D00219151300", "ABS-CBN (Telecommunication)" },
{ "3B9E95801FC78031E073FE211B66D0022A861300BE", "KPN, Netherlands (Telecommunication)" },
{ "3B9E95C00A1FC68031E073FE211B66D001830D58811E", "Mobile Paypass G199 NFC" }, { "3B9E95C00A1FC68031E073FE211B66D001830D58811E", "Mobile Paypass G199 NFC" },
{ "3B9E96008031C0654D4700000072F7418107", "Russian Magistra (UTF8: Magistra) smart card (eID)\nhttp://www.smart-park.ru/index.php/products/smartcards.html" }, { "3B9E96008031C0654D4700000072F7418107", "Russian Magistra (UTF8: Magistra) smart card (eID)\nhttp://www.smart-park.ru/index.php/products/smartcards.html" },
{ "3B9E96008031C0654D5300000072F7418107", "Smart-key for bank-client of MDM Bank (RU) with faktura.ru service (Bank)" }, { "3B9E96008031C0654D5300000072F7418107", "Smart-key for bank-client of MDM Bank (RU) with faktura.ru service (Bank)" },
@ -2506,6 +2517,7 @@ const static atr_t AtrTable[] = {
{ "3B9E96801FC68031E073FE211B66D0019F8F120002", "Russian 'Megafon' gsm sim card (Telecommunication)\nhttp://www.megafon.ru/" }, { "3B9E96801FC68031E073FE211B66D0019F8F120002", "Russian 'Megafon' gsm sim card (Telecommunication)\nhttp://www.megafon.ru/" },
{ "3B9E96801FC68031E073FE211B66D0019FBC100033", "sim beeline russia krasnodar (Telecommunication)" }, { "3B9E96801FC68031E073FE211B66D0019FBC100033", "sim beeline russia krasnodar (Telecommunication)" },
{ "3B9E96801FC68031E073FE211B66D0019FEF100060", "Infineon SLU14MCO480K2 (JavaCard)" }, { "3B9E96801FC68031E073FE211B66D0019FEF100060", "Infineon SLU14MCO480K2 (JavaCard)" },
{ "3B9E96801FC68031E073FE211B66D0024010150046", "Kyivstar USIM-card (Telecommunication)" },
{ "3B9E96801FC78031E073FE21136200498381900007", "Claro Brazil SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE21136200498381900007", "Claro Brazil SIM card (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D000282401000D", "United Mobile SIM" }, { "3B9E96801FC78031E073FE211B66D000282401000D", "United Mobile SIM" },
{ "3B9E96801FC78031E073FE211B66D0002B2D020004", "KTF SHOW GE-B1400 WCDMA USIM (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0002B2D020004", "KTF SHOW GE-B1400 WCDMA USIM (Telecommunication)" },
@ -2540,6 +2552,7 @@ const static atr_t AtrTable[] = {
{ "3B9E96801FC78031E073FE211B66D00199FE0E0068", "Finnish Sonera SIM-card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00199FE0E0068", "Finnish Sonera SIM-card (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D001A0041100B4", "Aldi Talk SIM card, Germany (Telecommunication)\nhttps://www.alditalk.de/talk" }, { "3B9E96801FC78031E073FE211B66D001A0041100B4", "Aldi Talk SIM card, Germany (Telecommunication)\nhttps://www.alditalk.de/talk" },
{ "3B9E96801FC78031E073FE211B66D001A01E1100AE", "Zevvle SIM Card (Telecommunication)\nhttps://zevvle.com" }, { "3B9E96801FC78031E073FE211B66D001A01E1100AE", "Zevvle SIM Card (Telecommunication)\nhttps://zevvle.com" },
{ "3B9E96801FC78031E073FE211B66D001A0741000C5", "USIM of Vodafone Germany (MCC 262, MNC 2) (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D001A0DD12006E", "USIM (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A0DD12006E", "USIM (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D001A0EC11005C", "Boost Mobile Prepaid Micro SIM Card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A0EC11005C", "Boost Mobile Prepaid Micro SIM Card (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D001A1121000A2", "OpenAirInerface (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1121000A2", "OpenAirInerface (Telecommunication)" },
@ -2565,6 +2578,7 @@ const static atr_t AtrTable[] = {
{ "3B9E96801FC78031E073FE211B66D00217F41200F3", "SIM card for Swedish operator Vimla! (Telecommunication)\nhttps://www.vimla.se" }, { "3B9E96801FC78031E073FE211B66D00217F41200F3", "SIM card for Swedish operator Vimla! (Telecommunication)\nhttps://www.vimla.se" },
{ "3B9E96801FC78031E073FE211B66D002194B120042", "halebop (swedish mobile provider) SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D002194B120042", "halebop (swedish mobile provider) SIM card (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D0022436140004", "SIM (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022436140004", "SIM (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D0022A6D140051", "Mobitel SIM from Sri Lanka (Telecommunication)\nhttps://mobitel.lk/" },
{ "3B9E96801FC78031E073FE211B66D0022A72130049", "SIM Card OI (Brazil) (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022A72130049", "SIM Card OI (Brazil) (Telecommunication)" },
{ "3B9E96801FC78031E073FE211B66D0022A861300BD", "Mobile Vikings SIM Card (Telecommunication)\nhttps://mobilevikings.com" }, { "3B9E96801FC78031E073FE211B66D0022A861300BD", "Mobile Vikings SIM Card (Telecommunication)\nhttps://mobilevikings.com" },
{ "3B9E96801FC78031E073FE211B66D0022A8F1400B3", "Telefonica USIM (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022A8F1400B3", "Telefonica USIM (Telecommunication)" },
@ -2575,6 +2589,7 @@ const static atr_t AtrTable[] = {
{ "3B9E96801FC78031E073FE211B66D00233AD140088", "4G-LTE (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00233AD140088", "4G-LTE (Telecommunication)" },
{ "3B9E96803FC3A08031E073FE211B630801140F9000D3", "KT Olleh LTE Warp SA-L 1670 (Telecommunication)" }, { "3B9E96803FC3A08031E073FE211B630801140F9000D3", "KT Olleh LTE Warp SA-L 1670 (Telecommunication)" },
{ "3B9E97801FC68031E073FE211B66D0019F7A1200F6", "Spectrun USA Sim Card (Telecommunication)" }, { "3B9E97801FC68031E073FE211B66D0019F7A1200F6", "Spectrun USA Sim Card (Telecommunication)" },
{ "3B9E97801FC68031E073FE211B66D0024011150046", "SIM Card for French mobile provider Unyc (Telecommunication)\nhttps://www.unyc.io/" },
{ "3B9E97801FC68031E073FE211B66D002401D15004A", "Telia Sim card for IoT (Telecommunication)" }, { "3B9E97801FC68031E073FE211B66D002401D15004A", "Telia Sim card for IoT (Telecommunication)" },
{ "3B9E97801FC68031E073FE211B66D0024027150070", "verymobile wind 3 (Telecommunication)\nhttps://verymobile.it/" }, { "3B9E97801FC68031E073FE211B66D0024027150070", "verymobile wind 3 (Telecommunication)\nhttps://verymobile.it/" },
{ "3B9E97801FC68031E073FE211B66D0025E7315003A", "Twilio Super SIM (Telecommunication)\nhttps://www.twilio.com/iot/super-sim-card" }, { "3B9E97801FC68031E073FE211B66D0025E7315003A", "Twilio Super SIM (Telecommunication)\nhttps://www.twilio.com/iot/super-sim-card" },
@ -2643,6 +2658,7 @@ const static atr_t AtrTable[] = {
{ "3B9F94801FC78031E073FE2113578681098698621880", "Oyeitimes 5G ISIM R16 (Telecommunication)\nhttps://www.oyeitimes.com/detail.php?id=535&ids=565&idt=&ide=&dd=1410" }, { "3B9F94801FC78031E073FE2113578681098698621880", "Oyeitimes 5G ISIM R16 (Telecommunication)\nhttps://www.oyeitimes.com/detail.php?id=535&ids=565&idt=&ide=&dd=1410" },
{ "3B9F94801FC78031E073FE21135786850686984218AB", "4G LTE blank USIM Green Card (Telecommunication)\nhttp://grcard.en.alibaba.com/product/60076835567-209365843/4G_LTE_blank_usim_card_for_4G_network.html" }, { "3B9F94801FC78031E073FE21135786850686984218AB", "4G LTE blank USIM Green Card (Telecommunication)\nhttp://grcard.en.alibaba.com/product/60076835567-209365843/4G_LTE_blank_usim_card_for_4G_network.html" },
{ "3B9F94801FC78031E073FE21136321150683079000F8", "Maroc Telecom 4G+ (Telecommunication)" }, { "3B9F94801FC78031E073FE21136321150683079000F8", "Maroc Telecom 4G+ (Telecommunication)" },
{ "3B9F94801FC78031E073FE21136700000000000070AA", "OMANTEL (Telecommunication)\nhttps://portal.omantel.om/Personal/mobile/hayyak" },
{ "3B9F94801FC78031E073FE21136761210D10000070F7", "Celcom XPAX (Telecommunication)\nhttps://www.celcom.com.my/personal/prepaid" }, { "3B9F94801FC78031E073FE21136761210D10000070F7", "Celcom XPAX (Telecommunication)\nhttps://www.celcom.com.my/personal/prepaid" },
{ "3B9F94801FC78031E073FE2119573C8660CFB902A0EE", "Gotanet SE USIM (Telecommunication)" }, { "3B9F94801FC78031E073FE2119573C8660CFB902A0EE", "Gotanet SE USIM (Telecommunication)" },
{ "3B9F94801FC78031E073FE2119573C8660CFBA02A0ED", "Gotanet DK USIM (Telecommunication)" }, { "3B9F94801FC78031E073FE2119573C8660CFBA02A0ED", "Gotanet DK USIM (Telecommunication)" },
@ -2774,6 +2790,7 @@ const static atr_t AtrTable[] = {
{ "3B9F96801F878031E073FE2119674A555473300948DB", "nano sim/usim card (Telecommunication)" }, { "3B9F96801F878031E073FE2119674A555473300948DB", "nano sim/usim card (Telecommunication)" },
{ "3B9F96801F878031E073FE2119674A555475300662F8", "SIM Card (Telecommunication)" }, { "3B9F96801F878031E073FE2119674A555475300662F8", "SIM Card (Telecommunication)" },
{ "3B9F96801F878031E073FE2119674A557330310746BE", "Hologram Developer Global IoT SIM Card (Telecommunication)\nhttps://hologram.io/store/global-iot-sim-card/17" }, { "3B9F96801F878031E073FE2119674A557330310746BE", "Hologram Developer Global IoT SIM Card (Telecommunication)\nhttps://hologram.io/store/global-iot-sim-card/17" },
{ "3B9F96801F878031E073FE2119674A55753031136288", "Zimbabwe sim card provider: ECONET (Telecommunication)" },
{ "3B9F96801F878031E073FE211B674A4C5275310451D5", "Test card provided with 4G/5G network from Amarisoft (Telecommunication)" }, { "3B9F96801F878031E073FE211B674A4C5275310451D5", "Test card provided with 4G/5G network from Amarisoft (Telecommunication)" },
{ "3B9F96801F878031E073FE211B674A4C7530300248A9", "Cardcentrics (Telecommunication)" }, { "3B9F96801F878031E073FE211B674A4C7530300248A9", "Cardcentrics (Telecommunication)" },
{ "3B9F96801F878031E073FE211B674A4C753034054BA9", "sysmoISIM-SJA2 (Telecommunication)\nhttps://osmocom.org/projects/cellular-infrastructure/wiki/SysmoISIM-SJA2" }, { "3B9F96801F878031E073FE211B674A4C753034054BA9", "sysmoISIM-SJA2 (Telecommunication)\nhttps://osmocom.org/projects/cellular-infrastructure/wiki/SysmoISIM-SJA2" },
@ -2944,6 +2961,7 @@ const static atr_t AtrTable[] = {
{ "3B9F96803FC7828031E073F62157574A330581053000CE", "COMPRION M2M eUICC (Telecommunication)" }, { "3B9F96803FC7828031E073F62157574A330581053000CE", "COMPRION M2M eUICC (Telecommunication)" },
{ "3B9F96803FC7828031E073F62157574A4D020B60010069", "eSIM GSMA Card (Telecommunication)\nhttps://www.gsma.com/newsroom/wp-content/uploads/SGP.22_v2.2.pdf" }, { "3B9F96803FC7828031E073F62157574A4D020B60010069", "eSIM GSMA Card (Telecommunication)\nhttps://www.gsma.com/newsroom/wp-content/uploads/SGP.22_v2.2.pdf" },
{ "3B9F96803FC7828031E073F62157574A4D020B60610009", "ting (Telecommunication)" }, { "3B9F96803FC7828031E073F62157574A4D020B60610009", "ting (Telecommunication)" },
{ "3B9F96803FC7828031E073FE211B57AA8660F0010004FB", "The eSIM.me Card (Telecommunication)\nhttps://esim.me/" },
{ "3B9F96803FC7828031E073FE211B57AA8660F0010011EE", "eSIM.me pluggable eSIM (Telecommunication)\nhttps://esim.me/" }, { "3B9F96803FC7828031E073FE211B57AA8660F0010011EE", "eSIM.me pluggable eSIM (Telecommunication)\nhttps://esim.me/" },
{ "3B9F96803FC7828031E073FE211B633A204E8300900031", "eSIM (Telecommunication)" }, { "3B9F96803FC7828031E073FE211B633A204E8300900031", "eSIM (Telecommunication)" },
{ "3B9F96803FC7828031E075F62157210355020B60500019", "st33g1m2 (Telecommunication)\nhttps://www.st.com/en/secure-mcus/st33g1m2.html" }, { "3B9F96803FC7828031E075F62157210355020B60500019", "st33g1m2 (Telecommunication)\nhttps://www.st.com/en/secure-mcus/st33g1m2.html" },
@ -3047,6 +3065,7 @@ const static atr_t AtrTable[] = {
{ "3BB813008131205D0057696E4361726402", "SmartCard for Windows 1.1" }, { "3BB813008131205D0057696E4361726402", "SmartCard for Windows 1.1" },
{ "3BB813008131FA524348544D4F494341A5", "citizen digital certificate (PKI)\nhttp://moica.nat.gov.tw/" }, { "3BB813008131FA524348544D4F494341A5", "citizen digital certificate (PKI)\nhttp://moica.nat.gov.tw/" },
{ "3BB897008131FE45FFFF148230502300F1", "UAE Emirates ID (eID)\nhttps://www.icp.gov.ae" }, { "3BB897008131FE45FFFF148230502300F1", "UAE Emirates ID (eID)\nhttps://www.icp.gov.ae" },
{ "3BB89700813FE45FFFF148230502300F", "UAE Emirates ID (eID)" },
{ "3BB89700C00831FE45FFFF148230502300B8", "Infineon SECORA ID X (JavaCard)" }, { "3BB89700C00831FE45FFFF148230502300B8", "Infineon SECORA ID X (JavaCard)" },
{ "3BB918008131FE9E8073FF614083000000DF", "Serbian Identity Card\nThis is the new Serbian biometric identity card (every adult cityzen\nmust have). The chip contains owners picture, name, date and place\nof birth, current address, unique ID number and fingerprint." }, { "3BB918008131FE9E8073FF614083000000DF", "Serbian Identity Card\nThis is the new Serbian biometric identity card (every adult cityzen\nmust have). The chip contains owners picture, name, date and place\nof birth, current address, unique ID number and fingerprint." },
{ "3BB9940040144747334D4838353330", "T D1 GSM card (Telecommunication)" }, { "3BB9940040144747334D4838353330", "T D1 GSM card (Telecommunication)" },
@ -3239,6 +3258,7 @@ const static atr_t AtrTable[] = {
{ "3BDB960080B1FE451F830031C064B0FC100007900005", "Oberthur Cosmo V7 debug card (SDK)" }, { "3BDB960080B1FE451F830031C064B0FC100007900005", "Oberthur Cosmo V7 debug card (SDK)" },
{ "3BDB960080B1FE451F830031C064B0FC10000F90000D", "ID-One PIV (that's the only non-numeric identifying mark) (PKI)" }, { "3BDB960080B1FE451F830031C064B0FC10000F90000D", "ID-One PIV (that's the only non-numeric identifying mark) (PKI)" },
{ "3BDB960080B1FE451F830031C064BAFC10000790000F", "Oberthur ID-One Cosmo v7.0 80K (eID)\nhttps://www.ssi.gouv.fr/uploads/IMG/certificat/ANSSI-CC-cible_2011-64en.pdf" }, { "3BDB960080B1FE451F830031C064BAFC10000790000F", "Oberthur ID-One Cosmo v7.0 80K (eID)\nhttps://www.ssi.gouv.fr/uploads/IMG/certificat/ANSSI-CC-cible_2011-64en.pdf" },
{ "3BDB960080B1FE451F830031C064BAFC10000F900007", "Oberthur ID-One Cosmo v7.0 (PKI)\nhttps://csrc.nist.rip/groups/STM/cmvp/documents/140-1/140sp/140sp1236.pdf" },
{ "3BDB960080B1FE451F830031C064BE1B0100019000FB", "Bank card" }, { "3BDB960080B1FE451F830031C064BE1B0100019000FB", "Bank card" },
{ "3BDB960080B1FE451F830031C064C30801000F90009B", "SIM Aruba (Italian provider)" }, { "3BDB960080B1FE451F830031C064C30801000F90009B", "SIM Aruba (Italian provider)" },
{ "3BDB960080B1FE451F830031C064C7FC100001900074", "Oberthur Cosmo (eID)\nhttp://www.stampit.org" }, { "3BDB960080B1FE451F830031C064C7FC100001900074", "Oberthur Cosmo (eID)\nhttp://www.stampit.org" },
@ -3247,6 +3267,7 @@ const static atr_t AtrTable[] = {
{ "3BDB960080B1FE451F830031E85427E6040007900084", "Polish encard (eID)" }, { "3BDB960080B1FE451F830031E85427E6040007900084", "Polish encard (eID)" },
{ "3BDB960080B1FE451F830031E85427E604000F90008C", "Token card from iBRE CompanyNet (mbank) (Bank)" }, { "3BDB960080B1FE451F830031E85427E604000F90008C", "Token card from iBRE CompanyNet (mbank) (Bank)" },
{ "3BDB960080B1FE451F834553544F4E49412D65494455", "Estonian Identity Card (ID-One Cosmo v8.1) (eID)" }, { "3BDB960080B1FE451F834553544F4E49412D65494455", "Estonian Identity Card (ID-One Cosmo v8.1) (eID)" },
{ "3BDB960080B1FE451F870031C1640958223607900019", "Idemia Solvo Fly 40 (JavaCard)" },
{ "3BDB960081B1FE451F0380F9A0000003080000100018", "Oberthur CS PIV End Point v1.08 FIPS201 Certified" }, { "3BDB960081B1FE451F0380F9A0000003080000100018", "Oberthur CS PIV End Point v1.08 FIPS201 Certified" },
{ "3BDB960081B1FE451F0380F9A0000003480000000149", "Fly Clear card" }, { "3BDB960081B1FE451F0380F9A0000003480000000149", "Fly Clear card" },
{ "3BDB960081B1FE451F8380F9A0000003080000100098", "Oberthur Cosmo v7 128K with PIV applet\nhttp://www.smartcardfocus.com/shop/ilp/id~410/p/index.shtml" }, { "3BDB960081B1FE451F8380F9A0000003080000100098", "Oberthur Cosmo v7 128K with PIV applet\nhttp://www.smartcardfocus.com/shop/ilp/id~410/p/index.shtml" },
@ -3344,6 +3365,7 @@ const static atr_t AtrTable[] = {
{ "3BDF96FF910131FE4680319052410264050200AC73D622C017", "Acos-ID (AUSTRIACARD's Operating System) (Other)\nhttps://www.austriacard.com/digital-security/solutions/card-solutions/acos-id/" }, { "3BDF96FF910131FE4680319052410264050200AC73D622C017", "Acos-ID (AUSTRIACARD's Operating System) (Other)\nhttps://www.austriacard.com/digital-security/solutions/card-solutions/acos-id/" },
{ "3BDF97008131FE588031B05202056405A100AC73D622C021", "Austrian healthcare insurance identification card (HealthCare)\nhttps://www.chipkarte.at" }, { "3BDF97008131FE588031B05202056405A100AC73D622C021", "Austrian healthcare insurance identification card (HealthCare)\nhttps://www.chipkarte.at" },
{ "3BDF970081B1FE451F838073CC91CBF9A0000003080000100078", "NASA PIV Card (Other)" }, { "3BDF970081B1FE451F838073CC91CBF9A0000003080000100078", "NASA PIV Card (Other)" },
{ "3BE000008131104505", "Emoney indonesia (Bank)" },
{ "3BE000008131204030", "SmarTEC" }, { "3BE000008131204030", "SmarTEC" },
{ "3BE000FF8131FE4514", "'JUKICARD', digitally sign tax documents in Japan" }, { "3BE000FF8131FE4514", "'JUKICARD', digitally sign tax documents in Japan" },
{ "3BE20000402049..", "Schlumberger Cryptoflex 4k" }, { "3BE20000402049..", "Schlumberger Cryptoflex 4k" },
@ -3432,6 +3454,7 @@ const static atr_t AtrTable[] = {
{ "3BEE00008131804280318066B0840C016E01830090008E", "MultiApp Cards (Easy 72K Type B and Combi 72K Type B)\nE.SUN Commercial bank debit master card (Bank)\nTaiwan EasyCard (Transport)\nhttps://www.easycard.com.tw/english/index.asp" }, { "3BEE00008131804280318066B0840C016E01830090008E", "MultiApp Cards (Easy 72K Type B and Combi 72K Type B)\nE.SUN Commercial bank debit master card (Bank)\nTaiwan EasyCard (Transport)\nhttps://www.easycard.com.tw/english/index.asp" },
{ "3BEE00008131804380318066B1A1110100F683009000", "Optelio/Desineo Cards (D72 FXR1)" }, { "3BEE00008131804380318066B1A1110100F683009000", "Optelio/Desineo Cards (D72 FXR1)" },
{ "3BEE00008131804380318066B1A11101A0F683009000", "Optelio D72 FXR1 (MD) T=1" }, { "3BEE00008131804380318066B1A11101A0F683009000", "Optelio D72 FXR1 (MD) T=1" },
{ "3BEE00008131804380318066B1A30401110B83009000D4", "Japan Post Bank cash card (Bank)\nhttps://www.jp-bank.japanpost.jp/kojin/chokin/sogou/kj_cho_sg_iccard.html" },
{ "3BEE00008131FE45003180718665016702A00A8390001B", "IBM JCOP 'Java Card 2.1.1' et 'Open Platform 2.0.1'" }, { "3BEE00008131FE45003180718665016702A00A8390001B", "IBM JCOP 'Java Card 2.1.1' et 'Open Platform 2.0.1'" },
{ "3BEE00008131FE4580318066409093060F1783019000FD", "Health insurance (HealthCare)" }, { "3BEE00008131FE4580318066409093060F1783019000FD", "Health insurance (HealthCare)" },
{ "3BEE00008131FE4580318066409093060F17830F9000F3", "IC card for the National Health Insurance, Taiwan" }, { "3BEE00008131FE4580318066409093060F17830F9000F3", "IC card for the National Health Insurance, Taiwan" },
@ -3579,6 +3602,7 @@ const static atr_t AtrTable[] = {
{ "3BF711000140967070370E6CB6D6", "Carte pour decodeur cable numerique (fourni par www.voo.be et\nwww.ledecodeur.be)" }, { "3BF711000140967070370E6CB6D6", "Carte pour decodeur cable numerique (fourni par www.voo.be et\nwww.ledecodeur.be)" },
{ "3BF711000140967070670E6CB6D6", "UK TopUp TV" }, { "3BF711000140967070670E6CB6D6", "UK TopUp TV" },
{ "3BF711000140967071090E6CB6D6", "Carte pour decodeur tele de Neuf Telecom TV" }, { "3BF711000140967071090E6CB6D6", "Carte pour decodeur tele de Neuf Telecom TV" },
{ "3BF71300008131FE4500C08AC80C658185", "NXP JCop (JavaCard)" },
{ "3BF71300008131FE45464F4D534F4D53A9", "Health card Russian Federation" }, { "3BF71300008131FE45464F4D534F4D53A9", "Health card Russian Federation" },
{ "3BF71300008131FE454A434F503234....", "NXP JCOP v2.4.x (see hist bytes for more info)" }, { "3BF71300008131FE454A434F503234....", "NXP JCOP v2.4.x (see hist bytes for more info)" },
{ "3BF71300008131FE4580654A5030310415", "Nichizeiren Denshi-shomei (eID)\nhttps://www.nichizeiren.or.jp/taxaccount/auth/fifth/" }, { "3BF71300008131FE4580654A5030310415", "Nichizeiren Denshi-shomei (eID)\nhttps://www.nichizeiren.or.jp/taxaccount/auth/fifth/" },
@ -3818,6 +3842,7 @@ const static atr_t AtrTable[] = {
{ "3BFF1300008131FE45434433690940000020202020202000F3", "VISA credit card (LBBW/Payback VISA) (Bank)" }, { "3BFF1300008131FE45434433690940000020202020202000F3", "VISA credit card (LBBW/Payback VISA) (Bank)" },
{ "3BFF1300008131FE454F574F4B31302D4A................", "OWOK (One Web, One Key) login card\nhttp://www.reiner-sct.com/owok/\nReiner SCT loginCard\nhttps://cardlogin.reiner-sct.com/" }, { "3BFF1300008131FE454F574F4B31302D4A................", "OWOK (One Web, One Key) login card\nhttp://www.reiner-sct.com/owok/\nReiner SCT loginCard\nhttps://cardlogin.reiner-sct.com/" },
{ "3BFF1300008131FE4D8025A00000005657444B3333300600D2", "Datakey DCOS model 330 (DKCCOS 6.0 token)" }, { "3BFF1300008131FE4D8025A00000005657444B3333300600D2", "Datakey DCOS model 330 (DKCCOS 6.0 token)" },
{ "3BFF1300918131FE4141434F532046696F6E6131204C6336F4", "TURKEY A101 HADI APP CARD (Bank)\nhttps://a101hadi.a101.com.tr/" },
{ "3BFF1300FF10000031C1738211064414D33470779000", "Visa Debit (Bank)\nhttps://www.chase.com/" }, { "3BFF1300FF10000031C1738211064414D33470779000", "Visa Debit (Bank)\nhttps://www.chase.com/" },
{ "3BFF1300FF10000031C173C821106441443533079000", "BRADESCO-CONTA SALARIO (Bank)" }, { "3BFF1300FF10000031C173C821106441443533079000", "BRADESCO-CONTA SALARIO (Bank)" },
{ "3BFF1300FF10000031C173C8211064414D3130079000", "Tangerine MasterCard (Bank)\nhttps://www.tangerine.ca/en/products/spending/creditcard/money-back/" }, { "3BFF1300FF10000031C173C8211064414D3130079000", "Tangerine MasterCard (Bank)\nhttps://www.tangerine.ca/en/products/spending/creditcard/money-back/" },
@ -3883,6 +3908,7 @@ const static atr_t AtrTable[] = {
{ "3BFF1800FF813150456563............................", "GeldKarte v3 (Germany)" }, { "3BFF1800FF813150456563............................", "GeldKarte v3 (Germany)" },
{ "3BFF1800FF8131FE4165630608710156000FB85073204712D8", "Commerzbank maestro (Bank)\nhttps://www.commerzbank.de/konten-zahlungsverkehr/produkte/girokonten/kostenloses-girokonto/" }, { "3BFF1800FF8131FE4165630608710156000FB85073204712D8", "Commerzbank maestro (Bank)\nhttps://www.commerzbank.de/konten-zahlungsverkehr/produkte/girokonten/kostenloses-girokonto/" },
{ "3BFF1800FF8131FE4165630608710156000FB8602AA0471231", "Debit card (Germany): Postbank - GeldKarte (EUR), girocard, V-PAY (Bank)\nhttps://www.postbank.de/" }, { "3BFF1800FF8131FE4165630608710156000FB8602AA0471231", "Debit card (Germany): Postbank - GeldKarte (EUR), girocard, V-PAY (Bank)\nhttps://www.postbank.de/" },
{ "3BFF1800FF8131FE41656306087102500023B8907360471271", "Debit card (Germany): Deutsche Kreditbank (DKB), ec-cash, (Bank)\nhttps://www.dkb.de/privatkunden/karten/girocard" },
{ "3BFF1800FF8131FE4165631116710156000F0902904E5711AC", "German Bank Card IDEMIA 9 Maestro/Girocard (Sparkasse S-Payment TPY 1974693D) (Bank)" }, { "3BFF1800FF8131FE4165631116710156000F0902904E5711AC", "German Bank Card IDEMIA 9 Maestro/Girocard (Sparkasse S-Payment TPY 1974693D) (Bank)" },
{ "3BFF1800FF8131FE450031C573C00180547615020105900074", "SIGILANCE NFC OpenPGP Smart Card (JavaCard)\nhttps://www.sigilance.com/" }, { "3BFF1800FF8131FE450031C573C00180547615020105900074", "SIGILANCE NFC OpenPGP Smart Card (JavaCard)\nhttps://www.sigilance.com/" },
{ "3BFF1800FF8131FE455448434331305445434F4744484E3224", "National Health Insurance Card, Taiwan" }, { "3BFF1800FF8131FE455448434331305445434F4744484E3224", "National Health Insurance Card, Taiwan" },
@ -3993,6 +4019,7 @@ const static atr_t AtrTable[] = {
{ "3BFF9600008131FE4380318065B0845651101201788290006A", "SafeNet eToken 5300 (PKI)" }, { "3BFF9600008131FE4380318065B0845651101201788290006A", "SafeNet eToken 5300 (PKI)" },
{ "3BFF9600008131FE4380318065B08456511012021082900001", "Nedap NexS N:Secure (eID)\nhttps://www.nsecure.nl/nl/" }, { "3BFF9600008131FE4380318065B08456511012021082900001", "Nedap NexS N:Secure (eID)\nhttps://www.nsecure.nl/nl/" },
{ "3BFF9600008131FE4380318065B0846160FB120FFD8290000C", "IDPrime 930 FIPS Level 2 (T=1 CT=96) (BAI3.1) (PKI)" }, { "3BFF9600008131FE4380318065B0846160FB120FFD8290000C", "IDPrime 930 FIPS Level 2 (T=1 CT=96) (BAI3.1) (PKI)" },
{ "3BFF9600008131FE4380318065B0846566FB12017882900085", "eToken 5110+ FIPS 140-2 Level 2 (JavaCard)" },
{ "3BFF9600008131FE4380318065B0846566FB120FFC8290000F", "SmartID 3930 FIDO Contact and Contactless card (PKI)\nhttps://www.smartcardfocus.com/shop/ilp/id~962/safenet-idprime-3930-fido-dual-interface-fips-l2/p/index.shtml" }, { "3BFF9600008131FE4380318065B0846566FB120FFC8290000F", "SmartID 3930 FIDO Contact and Contactless card (PKI)\nhttps://www.smartcardfocus.com/shop/ilp/id~962/safenet-idprime-3930-fido-dual-interface-fips-l2/p/index.shtml" },
{ "3BFF9600008131FE4380318065B0846669FB12FFFE829000F1", "IDCore3230 build 6.8, test APDU applet (JavaCard)" }, { "3BFF9600008131FE4380318065B0846669FB12FFFE829000F1", "IDCore3230 build 6.8, test APDU applet (JavaCard)" },
{ "3BFF9600008131FE4380318065B085040011120FFF829000E0", "Pakistan National identity card (eID)" }, { "3BFF9600008131FE4380318065B085040011120FFF829000E0", "Pakistan National identity card (eID)" },
@ -4024,6 +4051,7 @@ const static atr_t AtrTable[] = {
{ "3F2F008059AF0201013000000A0E83069F12", "Gemplus GemXplore" }, { "3F2F008059AF0201013000000A0E83069F12", "Gemplus GemXplore" },
{ "3F2F008059AF02010230000C0A0E831E9F16", "GSM-SIM (900MHz) card of the carrier 'Mannesmann Mobilfunk' for\ntheir network 'D2-Privat' - now known as Vodafone Mobilfunk\nhttp://www.vodafone.de/" }, { "3F2F008059AF02010230000C0A0E831E9F16", "GSM-SIM (900MHz) card of the carrier 'Mannesmann Mobilfunk' for\ntheir network 'D2-Privat' - now known as Vodafone Mobilfunk\nhttp://www.vodafone.de/" },
{ "3F2F008069AE0202013600000A0E833E9F16", "GSM-SIM e-plus (1800MHz)" }, { "3F2F008069AE0202013600000A0E833E9F16", "GSM-SIM e-plus (1800MHz)" },
{ "3F2F008069AF0204013600000A0E833E9F16", "Telia Mobitel GSM (Telecommunication)" },
{ "3F2F008069AF0204013600020A0E833E9F16", "GSM-SIM D2 CallYa (900MHz)" }, { "3F2F008069AF0204013600020A0E833E9F16", "GSM-SIM D2 CallYa (900MHz)" },
{ "3F2F008069AF0307015900000A0E833E9F16", "Nokia SIM Ph2 16K Ver2.0" }, { "3F2F008069AF0307015900000A0E833E9F16", "Nokia SIM Ph2 16K Ver2.0" },
{ "3F2F008069AF0307015900130A0E833E9F16", "Old Spanish Telefonica Movistar GSM SIM card manufactured by Gemplus" }, { "3F2F008069AF0307015900130A0E833E9F16", "Old Spanish Telefonica Movistar GSM SIM card manufactured by Gemplus" },

View file

@ -104,9 +104,7 @@ static int CIPURSEExchangeEx(bool activate_field, bool leave_field_on, sAPDU_t a
memcpy(result, securedata, rlen); memcpy(result, securedata, rlen);
} }
if (result_len != NULL) {
*result_len = rlen; *result_len = rlen;
}
if (sw != NULL) { if (sw != NULL) {
*sw = isw; *sw = isw;
@ -628,7 +626,7 @@ void CIPURSEPrintFileAttrEx(uint8_t *attr, size_t len, bool isDGI) {
} }
void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) { void CIPURSEPrintFileAttr(uint8_t *attr, size_t len) {
return CIPURSEPrintFileAttrEx(attr, len, false); CIPURSEPrintFileAttrEx(attr, len, false);
} }
void CIPURSEPrintFileUpdateAttr(uint8_t *attr, size_t len) { void CIPURSEPrintFileUpdateAttr(uint8_t *attr, size_t len) {

View file

@ -3279,9 +3279,9 @@ static int CmdNumCon(const char *Cmd) {
} radix_t; } radix_t;
radix_t radix[] = { radix_t radix[] = {
{"dec..... ", 10}, {"dec... ", 10},
{"hex..... 0x", 16}, {"hex... ", 16},
{"bin..... 0b", 2} {"bin... ", 2}
}; };
char s[600] = {0}; char s[600] = {0};
@ -3290,7 +3290,7 @@ static int CmdNumCon(const char *Cmd) {
for (uint8_t i = 0; i < ARRAYLEN(radix); i++) { for (uint8_t i = 0; i < ARRAYLEN(radix); i++) {
MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(&N, radix[i].radix, s, sizeof(s), &slen)); MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(&N, radix[i].radix, s, sizeof(s), &slen));
if (slen > 0) { if (slen > 0) {
PrintAndLogEx(INFO, "%s%s", radix[i].desc, s); PrintAndLogEx(SUCCESS, "%s%s", radix[i].desc, s);
} }
} }
@ -3451,6 +3451,72 @@ static int CmdAtrLookup(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdBinaryMap(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "data bmap",
"Breaks down a hex value to binary according a template\n"
" data bmap -d 16 -m 4,4\n"
"This will give two rows each with four bits",
"data bmap -d 3B\n"
"data bmap -d 3B -m 2,5,1\n"
);
void *argtable[] = {
arg_param_begin,
arg_str0("d", NULL, "<hex>", "hex string"),
arg_str0("m", NULL, "<str>", "binary template"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int hlen = 5;
uint8_t hex[5 + 1];
CLIGetStrWithReturn(ctx, 1, hex, &hlen);
int tlen = 40;
uint8_t template[40 + 1];
CLIGetStrWithReturn(ctx, 2, template, &tlen);
CLIParserFree(ctx);
char bits[(8 * 4) + 1] = {0};
hextobinstring_n(bits, (char *)hex, hlen);
if (tlen == 0) {
template[0] = '8';
template[1] = 0;
}
char *token = strtok((char *)template, ",");
// header
PrintAndLogEx(INFO, "---+---------------------------");
PrintAndLogEx(INFO, " | b0 b1 b2 b3 b4 b5 b6 b7");
PrintAndLogEx(INFO, "---+---------------------------");
uint8_t i = 0;
uint8_t cnt = 1;
int x = 0;
while (token != NULL) {
sscanf(token, "%d", &x);
PrintAndLogEx(INFO, " %d | %*.s" NOLF, cnt, i * 3, " ");
// incease with previous offset
x += i;
for (; i < (uint8_t)x; i++) {
PrintAndLogEx(NORMAL, "%c " NOLF, bits[7 - i]);
}
PrintAndLogEx(NORMAL, "");
token = strtok(NULL, ",");
cnt++;
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
@ -3493,6 +3559,7 @@ static command_t CommandTable[] = {
{"atr", CmdAtrLookup, AlwaysAvailable, "ATR lookup"}, {"atr", CmdAtrLookup, AlwaysAvailable, "ATR lookup"},
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"}, {"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"},
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"}, {"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},
{"bmap", CmdBinaryMap, AlwaysAvailable, "Convert hex value according a binary template"},
{"clear", CmdBuffClear, AlwaysAvailable, "Clears bigbuf on deviceside and graph window"}, {"clear", CmdBuffClear, AlwaysAvailable, "Clears bigbuf on deviceside and graph window"},
{"diff", CmdDiff, AlwaysAvailable, "Diff of input files"}, {"diff", CmdDiff, AlwaysAvailable, "Diff of input files"},
{"hexsamples", CmdHexsamples, IfPm3Present, "Dump big buffer as hex bytes"}, {"hexsamples", CmdHexsamples, IfPm3Present, "Dump big buffer as hex bytes"},

View file

@ -379,8 +379,7 @@ static int CmdFlashMemDump(const char *Cmd) {
} }
if (filename[0] != '\0') { if (filename[0] != '\0') {
saveFile(filename, ".bin", dump, len); pm3_save_dump(filename, dump, len, jsfRaw);
saveFileEML(filename, dump, len, 16);
} }
free(dump); free(dump);

View file

@ -370,14 +370,13 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
"Dumps device SPIFFS file to a local file\n" "Dumps device SPIFFS file to a local file\n"
"Size is handled by first sending a STAT command against file to verify existence", "Size is handled by first sending a STAT command against file to verify existence",
"mem spiffs dump -s tag.bin --> download binary file from device\n" "mem spiffs dump -s tag.bin --> download binary file from device\n"
"mem spiffs dump -s tag.bin -d aaa -e --> download tag.bin, save as aaa.eml format" "mem spiffs dump -s tag.bin -d a001 -e --> download tag.bin, save as `a001.bin`"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("s", "src", "<fn>", "SPIFFS file to save"), arg_str1("s", "src", "<fn>", "SPIFFS file to save"),
arg_str0("d", "dest", "<fn>", "file name to save to <w/o .bin>"), arg_str0("d", "dest", "<fn>", "file name to save to <w/o .bin>"),
arg_lit0("e", "eml", "also save in EML format"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -390,7 +389,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
char dest[FILE_PATH_SIZE] = {0}; char dest[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, FILE_PATH_SIZE, &dlen); CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, FILE_PATH_SIZE, &dlen);
bool eml = arg_get_lit(ctx, 3);
CLIParserFree(ctx); CLIParserFree(ctx);
// get size from spiffs itself ! // get size from spiffs itself !
@ -433,15 +431,6 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
else else
saveFile(fn, ".bin", dump, len); // default saveFile(fn, ".bin", dump, len); // default
if (eml) {
uint8_t eml_len = 16;
if (strstr(fn, "class") != NULL)
eml_len = 8;
else if (strstr(fn, "mfu") != NULL)
eml_len = 4;
saveFileEML(fn, dump, len, eml_len);
}
free(dump); free(dump);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -994,7 +994,7 @@ int SelectCard14443A_4_WithParameters(bool disconnect, bool verbose, iso14a_card
// check result // check result
if (resp.oldarg[0] == 0) { if (resp.oldarg[0] == 0) {
if (verbose) { if (verbose) {
PrintAndLogEx(FAILED, "No card in field"); PrintAndLogEx(WARNING, "No ISO1443-A Card in field");
} }
return PM3_ECARDEXCHANGE; return PM3_ECARDEXCHANGE;
} }
@ -1595,6 +1595,7 @@ typedef enum {
MTEMV = 128, MTEMV = 128,
MTFUDAN = 256, MTFUDAN = 256,
MTISO18092 = 512, MTISO18092 = 512,
MT424 = 1024,
} nxp_mifare_type_t; } nxp_mifare_type_t;
// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1 // Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1
@ -1723,7 +1724,7 @@ static int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) {
} }
printTag("NTAG 4xx"); printTag("NTAG 4xx");
type |= MTDESFIRE; type |= (MTDESFIRE | MT424);
} }
} else if ((sak & 0x04) == 0x04) { } else if ((sak & 0x04) == 0x04) {
printTag("Any MIFARE CL1"); printTag("Any MIFARE CL1");
@ -1920,6 +1921,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
bool isEMV = false; bool isEMV = false;
bool isFUDAN = false; bool isFUDAN = false;
bool isISO18092 = false; bool isISO18092 = false;
bool isNTAG424 = false;
int nxptype = MTNONE; int nxptype = MTNONE;
if (card.uidlen <= 4) { if (card.uidlen <= 4) {
@ -1929,6 +1931,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT); isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT);
isNTAG424 = ((nxptype & MT424) == MT424);
if ((nxptype & MTOTHER) == MTOTHER) if ((nxptype & MTOTHER) == MTOTHER)
isMifareClassic = true; isMifareClassic = true;
@ -1958,6 +1961,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE); isMifareDESFire = ((nxptype & MTDESFIRE) == MTDESFIRE);
isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); isMifarePlus = ((nxptype & MTPLUS) == MTPLUS);
isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT); isMifareUltralight = ((nxptype & MTULTRALIGHT) == MTULTRALIGHT);
isNTAG424 = ((nxptype & MT424) == MT424);
if ((nxptype & MTOTHER) == MTOTHER) if ((nxptype & MTOTHER) == MTOTHER)
isMifareClassic = true; isMifareClassic = true;
@ -2010,8 +2014,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
// ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc)
DropField(); DropField();
uint32_t tagT = GetHF14AMfU_Type(); uint64_t tagT = GetHF14AMfU_Type();
if (tagT != UL_ERROR) { if (tagT != MFU_TT_UL_ERROR) {
ul_print_type(tagT, 0); ul_print_type(tagT, 0);
isMifareUltralight = true; isMifareUltralight = true;
printTag("MIFARE Ultralight/C/NTAG Compatible"); printTag("MIFARE Ultralight/C/NTAG Compatible");
@ -2461,6 +2465,11 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
*/ */
} }
if (isNTAG424) {
PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf ntag424 info") "`");
}
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
DropField(); DropField();
return select_status; return select_status;
@ -2748,6 +2757,7 @@ int CmdHF14ANdefRead(const char *Cmd) {
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool verbose = arg_get_lit(ctx, 2); bool verbose = arg_get_lit(ctx, 2);
bool verbose2 = arg_get_lit(ctx, 2) > 1;
CLIParserFree(ctx); CLIParserFree(ctx);
bool activate_field = true; bool activate_field = true;
@ -2934,11 +2944,24 @@ int CmdHF14ANdefRead(const char *Cmd) {
memcpy(ndef_file + (i - offset), response, segment_size); memcpy(ndef_file + (i - offset), response, segment_size);
} }
if (fnlen != 0) { if (verbose2) {
saveFile(filename, ".bin", ndef_file, ndef_size); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("NDEF raw") " ----------------");
print_buffer(ndef_file, ndef_size, 1);
} }
NDEFRecordsDecodeAndPrint(ndef_file, ndef_size, verbose); NDEFRecordsDecodeAndPrint(ndef_file, ndef_size, verbose);
pm3_save_dump(filename, ndef_file, ndef_size, jsfNDEF);
if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -v`") " for more details");
} else {
if (verbose2 == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf 14a ndefread -vv`") " for more details");
}
}
free(ndef_file); free(ndef_file);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -1537,7 +1537,12 @@ static int CmdHF14BDump(const char *Cmd) {
print_sr_blocks(data, cardsize, card.uid); print_sr_blocks(data, cardsize, card.uid);
if (nosave == false) { if (nosave) {
PrintAndLogEx(INFO, "Called with no save option");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
// save to file // save to file
if (fnlen < 1) { if (fnlen < 1) {
PrintAndLogEx(INFO, "using UID as filename"); PrintAndLogEx(INFO, "using UID as filename");
@ -1546,8 +1551,7 @@ static int CmdHF14BDump(const char *Cmd) {
} }
size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE; size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE;
pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE); pm3_save_dump(filename, data, datalen, jsf14b_v2);
}
} }
return switch_off_field_14b(); return switch_off_field_14b();
@ -1697,7 +1701,7 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
// check result // check result
int status = resp.oldarg[0]; int status = resp.oldarg[0];
if (status < 0) { if (status < 0) {
PrintAndLogEx(ERR, "No card in field."); PrintAndLogEx(WARNING, "No ISO14443-B Card in field");
switch_off_field_14b(); switch_off_field_14b();
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -2121,9 +2125,13 @@ int CmdHF14BNdefRead(const char *Cmd) {
goto out; goto out;
} }
if (fnlen != 0) { // get total NDEF length before save. If fails, we save it all
saveFile(filename, ".bin", response + 2, resplen - 4); size_t n = 0;
} if (NDEFGetTotalLength(response + 2, resplen - 4, &n) != PM3_SUCCESS)
n = resplen - 4;
pm3_save_dump(filename, response + 2, n, jsfNDEF);
res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose); res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose);
out: out:
@ -2164,7 +2172,7 @@ static int CmdHF14BView(const char *Cmd) {
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_param_end arg_param_end
}; };

View file

@ -62,7 +62,7 @@
typedef struct { typedef struct {
uint8_t lock; uint8_t lock;
uint8_t block[4]; uint8_t block[8];
} t15memory_t; } t15memory_t;
// structure and database for uid -> tagtype lookups // structure and database for uid -> tagtype lookups
@ -849,7 +849,7 @@ static int CmdHF15Info(const char *Cmd) {
"hf 15 info -u E011223344556677" "hf 15 info -u E011223344556677"
); );
void *argtable[6 + 1] = {}; void *argtable[6 + 1] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_param_end; argtable[arglen++] = arg_param_end;
@ -1143,14 +1143,14 @@ static int CmdHF15ELoad(const char *Cmd) {
static int CmdHF15ESave(const char *Cmd) { static int CmdHF15ESave(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 15 esave", CLIParserInit(&ctx, "hf 15 esave",
"Save emulator memory into three files (BIN/EML/JSON) ", "Save emulator memory into two files (bin/json) ",
"hf 15 esave -f hf-15-01020304" "hf 15 esave -f hf-15-01020304"
"hf 15 esave -b 8 -c 42 -f hf-15-01020304" "hf 15 esave -b 8 -c 42 -f hf-15-01020304"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_int0("b", "blocksize", "<dec>", "block size, defaults to 4"), arg_int0(NULL, "bsize", "<dec>", "block size, defaults to 4"),
arg_int0("c", "count", "<dec>", "number of blocks to export, defaults to all"), arg_int0("c", "count", "<dec>", "number of blocks to export, defaults to all"),
arg_param_end arg_param_end
}; };
@ -1176,13 +1176,18 @@ static int CmdHF15ESave(const char *Cmd) {
} }
PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes);
if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(dump); free(dump);
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
pm3_save_dump(filename, dump, bytes, jsf15, blocksize); if (blocksize == 8) {
pm3_save_dump(filename, dump, bytes, jsf15_v3);
} else {
pm3_save_dump(filename, dump, bytes, jsf15_v2);
}
free(dump); free(dump);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1244,7 +1249,7 @@ static int CmdHF15EView(const char *Cmd) {
} }
PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes); PrintAndLogEx(INFO, "Downloading %u bytes from emulator memory", bytes);
if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(dump); free(dump);
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
@ -1360,12 +1365,13 @@ static int CmdHF15WriteAfi(const char *Cmd) {
"hf 15 writeafi -u E011223344556677 --afi 12 -p 0F0F0F0F" "hf 15 writeafi -u E011223344556677 --afi 12 -p 0F0F0F0F"
); );
void *argtable[5] = {}; void *argtable[] = {
argtable[0] = arg_param_begin; arg_param_begin,
argtable[1] = arg_str0("u", "uid", "<hex>", "full UID, 8 bytes"); arg_str0("u", "uid", "<hex>", "full UID, 8 bytes"),
argtable[2] = arg_int1(NULL, "afi", "<dec>", "AFI number (0-255)"); arg_int1(NULL, "afi", "<dec>", "AFI number (0-255)"),
argtable[3] = arg_str0("p", "pwd", "<hex>", "optional AFI/EAS password"); arg_str0("p", "pwd", "<hex>", "optional AFI/EAS password"),
argtable[4] = arg_param_end; arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1443,7 +1449,7 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
"hf 15 writedsfid -u E011223344556677 --dsfid 12" "hf 15 writedsfid -u E011223344556677 --dsfid 12"
); );
void *argtable[6 + 2] = {}; void *argtable[6 + 2] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_int1(NULL, "dsfid", "<dec>", "DSFID number (0-255)"); argtable[arglen++] = arg_int1(NULL, "dsfid", "<dec>", "DSFID number (0-255)");
argtable[arglen++] = arg_param_end; argtable[arglen++] = arg_param_end;
@ -1537,15 +1543,15 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
static int CmdHF15Dump(const char *Cmd) { static int CmdHF15Dump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 15 dump", CLIParserInit(&ctx, "hf 15 dump",
"This command dumps the contents of a ISO-15693 tag and save it to file", "This command dumps the contents of a ISO-15693 tag and save to file (bin/json)",
"hf 15 dump\n" "hf 15 dump\n"
"hf 15 dump -*\n" "hf 15 dump -*\n"
"hf 15 dump -u E011223344556677 -f hf-15-my-dump.bin" "hf 15 dump -u E011223344556677 -f hf-15-my-dump.bin"
); );
void *argtable[6 + 2] = {}; void *argtable[6 + 2] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_str0("f", "file", "<fn>", "filename of dump"), argtable[arglen++] = arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
argtable[arglen++] = arg_param_end; argtable[arglen++] = arg_param_end;
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1604,9 +1610,12 @@ static int CmdHF15Dump(const char *Cmd) {
// memory. // memory.
t15memory_t mem[256]; t15memory_t mem[256];
uint8_t data[256 * 4] = {0}; uint8_t data[256 * 8] = {0};
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
// keep track of which block length tag returned?
uint8_t blklen = 4;
for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) { for (int retry = 0; (retry < 5 && blocknum < 0x100); retry++) {
req[10] = blocknum; req[10] = blocknum;
@ -1646,9 +1655,15 @@ static int CmdHF15Dump(const char *Cmd) {
break; break;
} }
// lock byte value
mem[blocknum].lock = resp.data.asBytes[0]; mem[blocknum].lock = resp.data.asBytes[0];
memcpy(mem[blocknum].block, resp.data.asBytes + 1, 4);
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, 4); // is tag responding with 4 or 8 bytes?
if (resp.length == 11) {
blklen = 8;
}
memcpy(mem[blocknum].block, resp.data.asBytes + 1, blklen);
memcpy(data + (blocknum * 4), resp.data.asBytes + 1, blklen);
retry = 0; retry = 0;
blocknum++; blocknum++;
@ -1659,6 +1674,10 @@ static int CmdHF15Dump(const char *Cmd) {
DropField(); DropField();
if (blklen == 8) {
PrintAndLogEx(INFO, "8 byte block length detected");
}
PrintAndLogEx(NORMAL, "\n"); PrintAndLogEx(NORMAL, "\n");
PrintAndLogEx(INFO, "block# | data |lck| ascii"); PrintAndLogEx(INFO, "block# | data |lck| ascii");
PrintAndLogEx(INFO, "---------+--------------+---+----------"); PrintAndLogEx(INFO, "---------+--------------+---+----------");
@ -1672,9 +1691,9 @@ static int CmdHF15Dump(const char *Cmd) {
PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s" PrintAndLogEx(INFO, "%3d/0x%02X | %s | %s | %s"
, i , i
, i , i
, sprint_hex(mem[i].block, 4) , sprint_hex(mem[i].block, blklen)
, lck , lck
, sprint_ascii(mem[i].block, 4) , sprint_ascii(mem[i].block, blklen)
); );
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -1687,8 +1706,11 @@ static int CmdHF15Dump(const char *Cmd) {
FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid)); FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid));
} }
size_t datalen = blocknum * 4; if (blklen == 8) {
pm3_save_dump(filename, data, datalen, jsf15, 4); pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v3);
} else {
pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v2);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1771,7 +1793,7 @@ static int CmdHF15Readmulti(const char *Cmd) {
"hf 15 rdmulti -u E011223344556677 -b 12 --cnt 3 -> read three blocks" "hf 15 rdmulti -u E011223344556677 -b 12 --cnt 3 -> read three blocks"
); );
void *argtable[6 + 3] = {}; void *argtable[6 + 3] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_int1("b", NULL, "<dec>", "first page number (0-255)"); argtable[arglen++] = arg_int1("b", NULL, "<dec>", "first page number (0-255)");
argtable[arglen++] = arg_int1(NULL, "cnt", "<dec>", "number of pages (1-6)"); argtable[arglen++] = arg_int1(NULL, "cnt", "<dec>", "number of pages (1-6)");
@ -1907,7 +1929,7 @@ static int CmdHF15Readblock(const char *Cmd) {
"hf 15 rdbl -u E011223344556677 -b 12" "hf 15 rdbl -u E011223344556677 -b 12"
); );
void *argtable[6 + 2] = {}; void *argtable[6 + 2] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)"); argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)");
argtable[arglen++] = arg_param_end; argtable[arglen++] = arg_param_end;
@ -2000,12 +2022,13 @@ static int CmdHF15Readblock(const char *Cmd) {
return PM3_EWRONGANSWER; return PM3_EWRONGANSWER;
} }
// print response // print response
char lck[16] = {0}; char lck[16] = {0};
if (data[1]) { if (data[1]) {
snprintf(lck, sizeof(lck), _RED_("%d"), data[1]); snprintf(lck, sizeof(lck), _RED_("%02X"), data[1]);
} else { } else {
snprintf(lck, sizeof(lck), "%d", data[1]); snprintf(lck, sizeof(lck), "%02X", data[1]);
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "#%3d |lck| ascii", block); PrintAndLogEx(INFO, "#%3d |lck| ascii", block);
@ -2068,7 +2091,7 @@ static int CmdHF15Write(const char *Cmd) {
"hf 15 wrbl -u E011223344556677 -b 12 -d AABBCCDD" "hf 15 wrbl -u E011223344556677 -b 12 -d AABBCCDD"
); );
void *argtable[6 + 4] = {}; void *argtable[6 + 4] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)"); argtable[arglen++] = arg_int1("b", "blk", "<dec>", "page number (0-255)");
argtable[arglen++] = arg_str1("d", "data", "<hex>", "data, 4 bytes"); argtable[arglen++] = arg_str1("d", "data", "<hex>", "data, 4 bytes");
@ -2153,15 +2176,15 @@ static int CmdHF15Write(const char *Cmd) {
static int CmdHF15Restore(const char *Cmd) { static int CmdHF15Restore(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 15 restore", CLIParserInit(&ctx, "hf 15 restore",
"This command restore the contents of a dump file onto a ISO-15693 tag", "This command restore the contents of a dump file (bin/eml/json) onto a ISO-15693 tag",
"hf 15 restore\n" "hf 15 restore\n"
"hf 15 restore -*\n" "hf 15 restore -*\n"
"hf 15 restore -u E011223344556677 -f hf-15-my-dump.bin" "hf 15 restore -u E011223344556677 -f hf-15-my-dump.bin"
); );
void *argtable[6 + 5] = {}; void *argtable[6 + 5] = {0};
uint8_t arglen = arg_add_default(argtable); uint8_t arglen = arg_add_default(argtable);
argtable[arglen++] = arg_str0("f", "file", "<fn>", "filename of dump"), argtable[arglen++] = arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
argtable[arglen++] = arg_int0("r", "retry", "<dec>", "number of retries (def 3)"), argtable[arglen++] = arg_int0("r", "retry", "<dec>", "number of retries (def 3)"),
argtable[arglen++] = arg_int0(NULL, "bs", "<dec>", "block size (def 4)"), argtable[arglen++] = arg_int0(NULL, "bs", "<dec>", "block size (def 4)"),
argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_lit0("v", "verbose", "verbose output");
@ -2834,7 +2857,7 @@ static int CmdHF15View(const char *Cmd) {
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
// arg_lit0("z", "dense", "dense dump output style"), // arg_lit0("z", "dense", "dense dump output style"),
arg_param_end arg_param_end
}; };

View file

@ -414,9 +414,8 @@ static int CmdHFCryptoRFDump(const char *Cmd) {
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
} }
saveFileEML(filename, data, datalen, 4); pm3_save_dump(filename, data, datalen, jsfCryptorf);
saveFile(filename, ".bin", data, datalen);
// json?
return switch_off_field_cryptorf(); return switch_off_field_cryptorf();
} }
@ -424,13 +423,13 @@ static int CmdHFCryptoRFELoad(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cryptorf eload", CLIParserInit(&ctx, "hf cryptorf eload",
"Loads CryptoRF tag dump into emulator memory on device", "Loads CryptoRF tag dump (bin/eml/json) into emulator memory on device",
"hf cryptorf eload -f hf-cryptorf-0102030405-dump.bin\n" "hf cryptorf eload -f hf-cryptorf-0102030405-dump.bin\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -486,14 +485,14 @@ static int CmdHFCryptoRFESave(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf cryptorf esave", CLIParserInit(&ctx, "hf cryptorf esave",
"Save emulator memory to bin/eml/json file\n" "Save emulator memory to file (bin/json)\n"
"if filename is not supplied, UID will be used.", "if filename is not supplied, UID will be used.",
"hf cryptorf esave\n" "hf cryptorf esave\n"
"hf cryptorf esave -f filename" "hf cryptorf esave -f filename"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dumpfile"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -527,11 +526,7 @@ static int CmdHFCryptoRFESave(const char *Cmd) {
FillFileNameByUID(fptr, data, "-dump", 4); FillFileNameByUID(fptr, data, "-dump", 4);
} }
saveFile(filename, ".bin", data, numofbytes); pm3_save_dump(filename, data, numofbytes, jsfCryptorf);
//needs to change
saveFileEML(filename, data, numofbytes, 8);
//needs to change
saveFileJSON(filename, jsfRaw, data, numofbytes, NULL);
free(data); free(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -42,10 +42,6 @@
#define EMRTD_MAX_FILE_SIZE 35000 #define EMRTD_MAX_FILE_SIZE 35000
// ISO7816 commands // ISO7816 commands
#define EMRTD_SELECT 0xA4
#define EMRTD_EXTERNAL_AUTHENTICATE 0x82
#define EMRTD_GET_CHALLENGE 0x84
#define EMRTD_READ_BINARY 0xB0
#define EMRTD_P1_SELECT_BY_EF 0x02 #define EMRTD_P1_SELECT_BY_EF 0x02
#define EMRTD_P1_SELECT_BY_NAME 0x04 #define EMRTD_P1_SELECT_BY_NAME 0x04
#define EMRTD_P2_PROPRIETARY 0x0C #define EMRTD_P2_PROPRIETARY 0x0C
@ -124,7 +120,7 @@ static emrtd_hashalg_t hashalg_table[] = {
{"SHA-1", sha1hash, 20, 7, {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A}}, {"SHA-1", sha1hash, 20, 7, {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A}},
{"SHA-256", sha256hash, 32, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}}, {"SHA-256", sha256hash, 32, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}},
{"SHA-512", sha512hash, 64, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}}, {"SHA-512", sha512hash, 64, 11, {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}},
{NULL, NULL, 0, 0, {}} {NULL, NULL, 0, 0, {0}}
}; };
static emrtd_pacealg_t pacealg_table[] = { static emrtd_pacealg_t pacealg_table[] = {
@ -145,7 +141,7 @@ static emrtd_pacealg_t pacealg_table[] = {
{"ECDH, Integrated Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x02}}, {"ECDH, Integrated Mapping, AES-CMAC-128", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x02}},
{"ECDH, Integrated Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x03}}, {"ECDH, Integrated Mapping, AES-CMAC-192", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x03}},
{"ECDH, Integrated Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x04}}, {"ECDH, Integrated Mapping, AES-CMAC-256", NULL, {0x04, 0x00, 0x7F, 0x00, 0x07, 0x02, 0x02, 0x04, 0x04, 0x04}},
{NULL, NULL, {}} {NULL, NULL, {0}}
}; };
static emrtd_pacesdp_t pacesdp_table[] = { static emrtd_pacesdp_t pacesdp_table[] = {
@ -383,25 +379,25 @@ static void _emrtd_convert_fileid(uint16_t file, uint8_t *dataout) {
} }
static int emrtd_select_file_by_name(uint8_t namelen, uint8_t *name) { static int emrtd_select_file_by_name(uint8_t namelen, uint8_t *name) {
return emrtd_exchange_commands_noout((sAPDU_t) {0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_NAME, 0x0C, namelen, name}, false, true); return emrtd_exchange_commands_noout((sAPDU_t) {0, ISO7816_SELECT_FILE, EMRTD_P1_SELECT_BY_NAME, 0x0C, namelen, name}, false, true);
} }
static int emrtd_select_file_by_ef(uint16_t file_id) { static int emrtd_select_file_by_ef(uint16_t file_id) {
uint8_t data[2]; uint8_t data[2];
_emrtd_convert_fileid(file_id, data); _emrtd_convert_fileid(file_id, data);
return emrtd_exchange_commands_noout((sAPDU_t) {0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, sizeof(data), data}, false, true); return emrtd_exchange_commands_noout((sAPDU_t) {0, ISO7816_SELECT_FILE, EMRTD_P1_SELECT_BY_EF, 0x0C, sizeof(data), data}, false, true);
} }
static int emrtd_get_challenge(int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { static int emrtd_get_challenge(int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) {
return emrtd_exchange_commands((sAPDU_t) {0, EMRTD_GET_CHALLENGE, 0, 0, 0, NULL}, true, length, dataout, maxdataoutlen, dataoutlen, false, true); return emrtd_exchange_commands((sAPDU_t) {0, ISO7816_GET_CHALLENGE, 0, 0, 0, NULL}, true, length, dataout, maxdataoutlen, dataoutlen, false, true);
} }
static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) {
return emrtd_exchange_commands((sAPDU_t) {0, EMRTD_EXTERNAL_AUTHENTICATE, 0, 0, length, data}, true, length, dataout, maxdataoutlen, dataoutlen, false, true); return emrtd_exchange_commands((sAPDU_t) {0, ISO7816_EXTERNAL_AUTHENTICATION, 0, 0, length, data}, true, length, dataout, maxdataoutlen, dataoutlen, false, true);
} }
static int _emrtd_read_binary(int offset, int bytes_to_read, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { static int _emrtd_read_binary(int offset, int bytes_to_read, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) {
return emrtd_exchange_commands((sAPDU_t) {0, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, 0, NULL}, true, bytes_to_read, dataout, maxdataoutlen, dataoutlen, false, true); return emrtd_exchange_commands((sAPDU_t) {0, ISO7816_READ_BINARY, offset >> 8, offset & 0xFF, 0, NULL}, true, bytes_to_read, dataout, maxdataoutlen, dataoutlen, false, true);
} }
static void emrtd_bump_ssc(uint8_t *ssc) { static void emrtd_bump_ssc(uint8_t *ssc) {
@ -503,7 +499,7 @@ static bool emrtd_secure_select_file_by_ef(uint8_t *kenc, uint8_t *kmac, uint8_t
memcpy(data + (datalen + 3), do8e, 10); memcpy(data + (datalen + 3), do8e, 10);
PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc));
if (emrtd_exchange_commands((sAPDU_t) {0x0C, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, lc, data}, true, 0, response, sizeof(response), &resplen, false, true) == false) { if (emrtd_exchange_commands((sAPDU_t) {0x0C, ISO7816_SELECT_FILE, EMRTD_P1_SELECT_BY_EF, 0x0C, lc, data}, true, 0, response, sizeof(response), &resplen, false, true) == false) {
return false; return false;
} }
@ -552,7 +548,7 @@ static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, i
memcpy(data + 3, do8e, 10); memcpy(data + 3, do8e, 10);
PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc));
if (emrtd_exchange_commands((sAPDU_t) {0x0C, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, lc, data}, true, 0, dataout, maxdataoutlen, dataoutlen, false, true) == false) { if (emrtd_exchange_commands((sAPDU_t) {0x0C, ISO7816_READ_BINARY, offset >> 8, offset & 0xFF, lc, data}, true, 0, dataout, maxdataoutlen, dataoutlen, false, true) == false) {
return false; return false;
} }

View file

@ -566,7 +566,7 @@ static void reverse_3des_key(const uint8_t *master_key, int length, uint8_t *rev
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
reverse_master_key[i] = master_key[(length - 1) - i]; reverse_master_key[i] = master_key[(length - 1) - i];
} }
}; }
/** /**
* Command parser for auth1 * Command parser for auth1

View file

@ -235,14 +235,14 @@ static int CmdHFFudanReader(const char *Cmd) {
static int CmdHFFudanDump(const char *Cmd) { static int CmdHFFudanDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf fudan dump", CLIParserInit(&ctx, "hf fudan dump",
"Dump FUDAN tag to binary file\n" "Dump FUDAN tag to file (bin/json)\n"
"If no <name> given, UID will be used as filename", "If no <name> given, UID will be used as filename",
"hf fudan dump -f mydump --> dump using filename\n" "hf fudan dump -f mydump --> dump using filename\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -339,14 +339,7 @@ static int CmdHFFudanDump(const char *Cmd) {
free(fptr); free(fptr);
} }
saveFile(dataFilename, ".bin", (uint8_t *)carddata, sizeof(carddata)); pm3_save_dump(dataFilename, (uint8_t *)carddata, sizeof(carddata), jsfFudan);
saveFileEML(dataFilename, (uint8_t *)carddata, sizeof(carddata), MAX_FUDAN_BLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = (uint8_t *)carddata;
xdump.dumplen = sizeof(carddata);
saveFileJSON(dataFilename, jsfFudan, (uint8_t *)&xdump, sizeof(xdump), NULL);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -460,7 +453,7 @@ static int CmdHFFudanView(const char *Cmd) {
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);

File diff suppressed because it is too large Load diff

View file

@ -112,27 +112,25 @@ static int decode_and_print_memory(uint16_t card_size, const uint8_t *input_buff
int fl = 0; int fl = 0;
if (data[6] == 0xec) { if (data[6] == 0xEC) {
strncpy(token_type, "XAM", sizeof(token_type) - 1); strncpy(token_type, "XAM", sizeof(token_type) - 1);
fl = 1; fl = 1;
stamp_len = 0x0c - (data[5] >> 4); stamp_len = 0x0c - (data[5] >> 4);
} else { } else {
switch (data[5] & 0x7f) {
case 0x00 ... 0x2f: uint8_t tmp = data[5] & 0x7F;
if (tmp <= 0x2F) {
strncpy(token_type, "IAM", sizeof(token_type) - 1); strncpy(token_type, "IAM", sizeof(token_type) - 1);
fl = (0x2f - (data[5] & 0x7f)) + 1; fl = (0x2F - tmp) + 1;
break; } else if (tmp >= 0x30 && tmp <= 0x6F) {
case 0x30 ... 0x6f:
strncpy(token_type, "SAM", sizeof(token_type) - 1); strncpy(token_type, "SAM", sizeof(token_type) - 1);
fl = (0x6f - (data[5] & 0x7f)) + 1; fl = (0x6F - tmp) + 1;
break; } else if (tmp >= 0x70 && tmp <= 0x7F) {
case 0x70 ... 0x7f:
strncpy(token_type, "GAM", sizeof(token_type) - 1); strncpy(token_type, "GAM", sizeof(token_type) - 1);
fl = (0x7f - (data[5] & 0x7f)) + 1; fl = (0x7F - tmp) + 1;
break;
} }
stamp_len = 0xfc - data[6]; stamp_len = 0xFC - data[6];
} }
PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x) Token Type=" _YELLOW_("%s") " (OLE=%01u) OL=%02u FL=%02u", PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x) Token Type=" _YELLOW_("%s") " (OLE=%01u) OL=%02u FL=%02u",
@ -858,7 +856,7 @@ static int CmdLegicReader(const char *Cmd) {
static int CmdLegicDump(const char *Cmd) { static int CmdLegicDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic dump", CLIParserInit(&ctx, "hf legic dump",
"Read all memory from LEGIC Prime tags and saves to (bin/eml/json) dump file\n" "Read all memory from LEGIC Prime tags and saves to (bin/json) dump file\n"
"It autodetects card type (MIM22, MIM256, MIM1024)", "It autodetects card type (MIM22, MIM256, MIM1024)",
"hf legic dump --> use UID as filename\n" "hf legic dump --> use UID as filename\n"
"hf legic dump -f myfile \n" "hf legic dump -f myfile \n"
@ -951,7 +949,7 @@ static int CmdLegicDump(const char *Cmd) {
FillFileNameByUID(filename, data, "-dump", 4); FillFileNameByUID(filename, data, "-dump", 4);
} }
pm3_save_dump(filename, data, readlen, jsfLegic, LEGIC_BLOCK_SIZE); pm3_save_dump(filename, data, readlen, jsfLegic_v2);
free(data); free(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -966,7 +964,7 @@ static int CmdLegicRestore(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "Filename to restore"), arg_str1("f", "file", "<fn>", "Specify a filename to restore"),
arg_lit0(NULL, "ob", "obfuscate dump data (xor with MCC)"), arg_lit0(NULL, "ob", "obfuscate dump data (xor with MCC)"),
arg_param_end arg_param_end
}; };
@ -1119,7 +1117,7 @@ static int CmdLegicELoad(const char *Cmd) {
static int CmdLegicESave(const char *Cmd) { static int CmdLegicESave(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic esave", CLIParserInit(&ctx, "hf legic esave",
"Saves a (bin/eml/json) dump file of emulator memory", "Saves a (bin/json) dump file of emulator memory",
"hf legic esave --> uses UID as filename\n" "hf legic esave --> uses UID as filename\n"
"hf legic esave -f myfile --22\n" "hf legic esave -f myfile --22\n"
"hf legic esave -f myfile --22 --de\n" "hf legic esave -f myfile --22 --de\n"
@ -1188,7 +1186,7 @@ static int CmdLegicESave(const char *Cmd) {
legic_xor(data, numofbytes); legic_xor(data, numofbytes);
} }
pm3_save_dump(filename, data, numofbytes, jsfLegic, LEGIC_BLOCK_SIZE); pm3_save_dump(filename, data, numofbytes, jsfLegic_v2);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1406,7 +1404,7 @@ static int CmdLegicView(const char *Cmd) {
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "Filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_param_end arg_param_end
}; };

View file

@ -655,12 +655,12 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf lto wrbl", CLIParserInit(&ctx, "hf lto wrbl",
"Write data to block on LTO tag", "Write data to block on LTO tag",
"hf lto wrbl --block 128 -d 0001020304050607080910111213141516171819202122232425262728293031"); "hf lto wrbl --blk 128 -d 0001020304050607080910111213141516171819202122232425262728293031");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("d", "data", "<hex>", "32 bytes of data to write (64 hex symbols, no spaces)"), arg_str1("d", "data", "<hex>", "32 bytes of data to write (64 hex symbols, no spaces)"),
arg_int1(NULL, "block", "<dec>", "The block number to write to as an integer"), arg_int1(NULL, "blk", "<dec>", "The block number to write to as an integer"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -771,8 +771,7 @@ static int CmdHfLTODump(const char *Cmd) {
char *fptr = filename + snprintf(filename, sizeof(filename), "hf-lto-"); char *fptr = filename + snprintf(filename, sizeof(filename), "hf-lto-");
FillFileNameByUID(fptr, dump, "-dump", 5); FillFileNameByUID(fptr, dump, "-dump", 5);
} }
saveFile(filename, ".bin", dump, dump_len); pm3_save_dump(filename, dump, dump_len, jsfLto);
saveFileEML(filename, dump, dump_len, 32);
free(dump); free(dump);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

File diff suppressed because it is too large Load diff

View file

@ -372,8 +372,7 @@ static int mfdes_get_info(mfdes_info_res_t *info) {
} }
// --- GET SIGNATURE // --- GET SIGNATURE
static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) { int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len) {
(void)card_type;
if (uid == NULL) { if (uid == NULL) {
PrintAndLogEx(DEBUG, "UID=NULL"); PrintAndLogEx(DEBUG, "UID=NULL");
@ -445,7 +444,7 @@ static void swap24(uint8_t *data) {
uint8_t tmp = data[0]; uint8_t tmp = data[0];
data[0] = data[2]; data[0] = data[2];
data[2] = tmp; data[2] = tmp;
}; }
// default parameters // default parameters
static uint8_t defaultKeyNum = 0; static uint8_t defaultKeyNum = 0;
@ -742,7 +741,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
res = DesfireReadSignature(&dctx, 0x00, signature, &signature_len); res = DesfireReadSignature(&dctx, 0x00, signature, &signature_len);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
if (signature_len == 56) if (signature_len == 56)
desfire_print_signature(info.uid, info.uidlen, signature, signature_len, cardtype); desfire_print_signature(info.uid, info.uidlen, signature, signature_len);
else else
PrintAndLogEx(WARNING, "--- GetSignature returned wrong signature length: %zu", signature_len); PrintAndLogEx(WARNING, "--- GetSignature returned wrong signature length: %zu", signature_len);
} else { } else {
@ -808,9 +807,9 @@ static int CmdHF14ADesInfo(const char *Cmd) {
iso14a_card_select_t card; iso14a_card_select_t card;
res = SelectCard14443A_4(true, false, &card); res = SelectCard14443A_4(true, false, &card);
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
static const char STANDALONE_DESFIRE[] = { 0x75, 0x77, 0x81, 0x02 }; static const uint8_t STANDALONE_DESFIRE[] = { 0x75, 0x77, 0x81, 0x02 };
static const char JCOP_DESFIRE[] = { 0x75, 0xf7, 0xb1, 0x02 }; static const uint8_t JCOP_DESFIRE[] = { 0x75, 0xf7, 0xb1, 0x02 };
static const char JCOP3_DESFIRE[] = { 0x78, 0x77, 0x71, 0x02 }; static const uint8_t JCOP3_DESFIRE[] = { 0x78, 0x77, 0x71, 0x02 };
if (card.sak == 0x20) { if (card.sak == 0x20) {
@ -1126,9 +1125,9 @@ static int CmdHF14aDesChk(const char *Cmd) {
CLIParserInit(&ctx, "hf mfdes chk", CLIParserInit(&ctx, "hf mfdes chk",
"Checks keys with MIFARE DESFire card.", "Checks keys with MIFARE DESFire card.",
"hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n" "hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n"
"hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card\n" "hf mfdes chk -d mfdes_default_keys -> check keys against all existing aid on card\n"
"hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys from dictionary against aid 0x123456\n" "hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys against aid 0x123456\n"
"hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json\n" "hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to `keys.json`\n"
"hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00"); "hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00");
void *argtable[] = { void *argtable[] = {

View file

@ -28,6 +28,8 @@ char *getVersionStr(uint8_t major, uint8_t minor);
int getKeySettings(uint8_t *aid); int getKeySettings(uint8_t *aid);
*/ */
int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len);
// Ev1 card limits // Ev1 card limits
#define MAX_NUM_KEYS 0x0F #define MAX_NUM_KEYS 0x0F
#define MAX_APPLICATION_COUNT 28 #define MAX_APPLICATION_COUNT 28

View file

@ -1384,15 +1384,15 @@ static int CmdHFMFPChk(const char *Cmd) {
static int CmdHFMFPDump(const char *Cmd) { static int CmdHFMFPDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfp dump", CLIParserInit(&ctx, "hf mfp dump",
"Dump MIFARE Plus tag to binary file\n" "Dump MIFARE Plus tag to file (bin/json)\n"
"If no <name> given, UID will be used as filename", "If no <name> given, UID will be used as filename",
"hf mfp dump\n" "hf mfp dump\n"
"hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n"); "hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_str0("k", "keys", "<fn>", "filename of keys"), arg_str0("k", "keys", "<fn>", "Specify a filename for keys file"),
arg_lit0(NULL, "ns", "no save to file"), arg_lit0(NULL, "ns", "no save to file"),
arg_lit0("v", "verbose", "Verbose mode"), arg_lit0("v", "verbose", "Verbose mode"),
arg_param_end arg_param_end
@ -1448,14 +1448,7 @@ static int CmdHFMFPDump(const char *Cmd) {
free(fptr); free(fptr);
} }
saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES); pm3_save_mf_dump(filename, dump, MIFARE_4K_MAX_BYTES, jsfCardMemory);
saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE);
iso14a_mf_extdump_t xdump;
xdump.card_info = card;
xdump.dump = mem;
xdump.dumplen = MIFARE_4K_MAX_BYTES;
saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
*/ */
free(mem); free(mem);
return PM3_SUCCESS; return PM3_SUCCESS;
@ -1746,16 +1739,19 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
print_buffer(data, datalen, 1); print_buffer(data, datalen, 1);
} }
if (fnlen != 0) {
saveFile(filename, ".bin", data, datalen);
}
res = NDEFDecodeAndPrint(data, datalen, verbose); res = NDEFDecodeAndPrint(data, datalen, verbose);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");
res = NDEFRecordsDecodeAndPrint(data, datalen, verbose); res = NDEFRecordsDecodeAndPrint(data, datalen, verbose);
} }
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(data, datalen, &n) != PM3_SUCCESS)
n = datalen;
pm3_save_dump(filename, data, n, jsfNDEF);
if (verbose == false) { if (verbose == false) {
PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details"); PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mfp ndefread -v`") " for more details");
} else { } else {

View file

@ -51,6 +51,7 @@
#define MAX_MY_D_MOVE 0x25 #define MAX_MY_D_MOVE 0x25
#define MAX_MY_D_MOVE_LEAN 0x0F #define MAX_MY_D_MOVE_LEAN 0x0F
#define MAX_UL_NANO_40 0x0A #define MAX_UL_NANO_40 0x0A
#define MAX_UL_AES 0x37
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -69,16 +70,25 @@ static uint8_t default_pwd_pack[][4] = {
{0x4E, 0x45, 0x78, 0x54}, // NExT {0x4E, 0x45, 0x78, 0x54}, // NExT
}; };
static uint32_t UL_TYPES_ARRAY[] = { static uint64_t UL_TYPES_ARRAY[] = {
UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, MFU_TT_UNKNOWN, MFU_TT_UL,
NTAG, NTAG_203, NTAG_210, NTAG_212, MFU_TT_UL_C, MFU_TT_UL_EV1_48,
NTAG_213, NTAG_215, NTAG_216, MFU_TT_UL_EV1_128, MFU_TT_NTAG,
MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, MFU_TT_NTAG_203, MFU_TT_NTAG_210,
NTAG_I2C_1K, NTAG_I2C_2K, NTAG_I2C_1K_PLUS, NTAG_I2C_2K_PLUS, MFU_TT_NTAG_212, MFU_TT_NTAG_213,
FUDAN_UL, NTAG_213_F, NTAG_216_F, UL_EV1, UL_NANO_40, MFU_TT_NTAG_215, MFU_TT_NTAG_216,
NTAG_213_TT, NTAG_213_C, MFU_TT_MY_D, MFU_TT_MY_D_NFC,
MAGIC_1A, MAGIC_1B, MAGIC_NTAG, MFU_TT_MY_D_MOVE, MFU_TT_MY_D_MOVE_NFC,
NTAG_210u, UL_MAGIC, UL_C_MAGIC MFU_TT_MY_D_MOVE_LEAN, MFU_TT_NTAG_I2C_1K,
MFU_TT_NTAG_I2C_2K, MFU_TT_NTAG_I2C_1K_PLUS,
MFU_TT_NTAG_I2C_2K_PLUS, MFU_TT_FUDAN_UL,
MFU_TT_NTAG_213_F, MFU_TT_NTAG_216_F,
MFU_TT_UL_EV1, MFU_TT_UL_NANO_40,
MFU_TT_NTAG_213_TT, MFU_TT_NTAG_213_C,
MFU_TT_MAGIC_1A, MFU_TT_MAGIC_1B,
MFU_TT_MAGIC_NTAG, MFU_TT_NTAG_210u,
MFU_TT_UL_MAGIC, MFU_TT_UL_C_MAGIC,
MFU_TT_UL_AES
}; };
static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = { static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
@ -99,7 +109,7 @@ static uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
// MAGIC_1A, MAGIC_1B, MAGIC_NTAG, // MAGIC_1A, MAGIC_1B, MAGIC_NTAG,
MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_NTAG_216,
// NTAG_210u, UL_MAGIC, UL_C_MAGIC // NTAG_210u, UL_MAGIC, UL_C_MAGIC
MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS MAX_NTAG_210, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_UL_AES
}; };
//------------------------------------ //------------------------------------
@ -372,8 +382,8 @@ static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t pac
return len; return len;
} }
static int ul_auth_select(iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) { static int ul_auth_select(iso14a_card_select_t *card, uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, uint8_t *pack, uint8_t packSize) {
if (hasAuthKey && (tagtype & UL_C)) { if (hasAuthKey && (tagtype & MFU_TT_UL_C)) {
//will select card automatically and close connection on error //will select card automatically and close connection on error
if (!ulc_authentication(authkey, false)) { if (!ulc_authentication(authkey, false)) {
PrintAndLogEx(WARNING, "Authentication Failed UL-C"); PrintAndLogEx(WARNING, "Authentication Failed UL-C");
@ -420,7 +430,6 @@ static int ulev1_readTearing(uint8_t counter, uint8_t *response, uint16_t respon
} }
static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) { static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) {
uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00}; uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00};
int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength);
return len; return len;
@ -442,16 +451,16 @@ static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) {
static int ul_fudan_check(void) { static int ul_fudan_check(void) {
iso14a_card_select_t card; iso14a_card_select_t card;
if (!ul_select(&card)) if (!ul_select(&card))
return UL_ERROR; return MFU_TT_UL_ERROR;
uint8_t cmd[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa7}; //wrong crc on purpose should be 0xa8 uint8_t cmd[4] = {ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa7}; //wrong crc on purpose should be 0xa8
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 4, 0, cmd, sizeof(cmd)); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 4, 0, cmd, sizeof(cmd));
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return UL_ERROR; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return MFU_TT_UL_ERROR;
if (resp.oldarg[0] != 1) return UL_ERROR; if (resp.oldarg[0] != 1) return MFU_TT_UL_ERROR;
return (!resp.data.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP return (!resp.data.asBytes[0]) ? MFU_TT_FUDAN_UL : MFU_TT_UL; //if response == 0x00 then Fudan, else Genuine NXP
} }
static int ul_print_default(uint8_t *data, uint8_t *real_uid) { static int ul_print_default(uint8_t *data, uint8_t *real_uid) {
@ -623,7 +632,7 @@ static int ndef_print_CC(uint8_t *data) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int ul_print_type(uint32_t tagtype, uint8_t spaces) { int ul_print_type(uint64_t tagtype, uint8_t spaces) {
if (spaces > 10) if (spaces > 10)
spaces = 10; spaces = 10;
@ -631,73 +640,73 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
char typestr[100]; char typestr[100];
memset(typestr, 0x00, sizeof(typestr)); memset(typestr, 0x00, sizeof(typestr));
if (tagtype & UL) if (tagtype & MFU_TT_UL)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1)"), spaces, "");
else if (tagtype & UL_C) else if (tagtype & MFU_TT_UL_C)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC)"), spaces, "");
else if (tagtype & UL_NANO_40) else if (tagtype & MFU_TT_UL_NANO_40)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spaces, "");
else if (tagtype & UL_EV1_48) else if (tagtype & MFU_TT_UL_EV1_48)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spaces, "");
else if (tagtype & UL_EV1_128) else if (tagtype & MFU_TT_UL_EV1_128)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spaces, "");
else if (tagtype & UL_EV1) else if (tagtype & MFU_TT_UL_EV1)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spaces, "");
else if (tagtype & NTAG) else if (tagtype & MFU_TT_NTAG)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces, "");
else if (tagtype & NTAG_203) else if (tagtype & MFU_TT_NTAG_203)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces, "");
else if (tagtype & NTAG_210u) else if (tagtype & MFU_TT_NTAG_210u)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210u (micro) 48bytes (NT2L1001G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210u (micro) 48bytes (NT2L1001G0DU)"), spaces, "");
else if (tagtype & NTAG_210) else if (tagtype & MFU_TT_NTAG_210)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces, "");
else if (tagtype & NTAG_212) else if (tagtype & MFU_TT_NTAG_212)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spaces, "");
else if (tagtype & NTAG_213) else if (tagtype & MFU_TT_NTAG_213)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, "");
else if (tagtype & NTAG_213_F) else if (tagtype & MFU_TT_NTAG_213_F)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, "");
else if (tagtype & NTAG_213_C) else if (tagtype & MFU_TT_NTAG_213_C)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213C 144bytes (NT2H1311C1DTL)"), spaces, "");
else if (tagtype & NTAG_213_TT) else if (tagtype & MFU_TT_NTAG_213_TT)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, "");
else if (tagtype & NTAG_215) else if (tagtype & MFU_TT_NTAG_215)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces, "");
else if (tagtype & NTAG_216) else if (tagtype & MFU_TT_NTAG_216)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spaces, "");
else if (tagtype & NTAG_216_F) else if (tagtype & MFU_TT_NTAG_216_F)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spaces, "");
else if (tagtype & NTAG_I2C_1K) else if (tagtype & MFU_TT_NTAG_I2C_1K)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spaces, "");
else if (tagtype & NTAG_I2C_2K) else if (tagtype & MFU_TT_NTAG_I2C_2K)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spaces, "");
else if (tagtype & NTAG_I2C_1K_PLUS) else if (tagtype & MFU_TT_NTAG_I2C_1K_PLUS)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spaces, "");
else if (tagtype & NTAG_I2C_2K_PLUS) else if (tagtype & MFU_TT_NTAG_I2C_2K_PLUS)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spaces, "");
else if (tagtype & MY_D) else if (tagtype & MFU_TT_MY_D)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spaces, "");
else if (tagtype & MY_D_NFC) else if (tagtype & MFU_TT_MY_D_NFC)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spaces, "");
else if (tagtype & MY_D_MOVE) else if (tagtype & MFU_TT_MY_D_MOVE)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spaces, "");
else if (tagtype & MY_D_MOVE_NFC) else if (tagtype & MFU_TT_MY_D_MOVE_NFC)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spaces, "");
else if (tagtype & MY_D_MOVE_LEAN) else if (tagtype & MFU_TT_MY_D_MOVE_LEAN)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spaces, "");
else if (tagtype & FUDAN_UL) else if (tagtype & MFU_TT_FUDAN_UL)
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible)"), spaces, ""); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible)"), spaces, "");
else else
snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("Unknown %06x"), spaces, "", tagtype); snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("Unknown %06" PRIx64), spaces, "", tagtype);
bool ismagic = ((tagtype & MAGIC) == MAGIC); bool ismagic = ((tagtype & MFU_TT_MAGIC) == MFU_TT_MAGIC);
if (ismagic) if (ismagic)
snprintf(typestr + strlen(typestr), 4, " ("); snprintf(typestr + strlen(typestr), 4, " (");
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MAGIC) ? _GREEN_("magic") : ""); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), " %s ", (tagtype & MFU_TT_MAGIC) ? _GREEN_("magic") : "");
tagtype &= ~(MAGIC); tagtype &= ~(MFU_TT_MAGIC);
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1A) ? _GREEN_("Gen 1a") : ""); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MFU_TT_MAGIC_1A) ? _GREEN_("Gen 1a") : "");
snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MAGIC_1B) ? _GREEN_("Gen 1b") : ""); snprintf(typestr + strlen(typestr), sizeof(typestr) - strlen(typestr), "%s", (tagtype & MFU_TT_MAGIC_1B) ? _GREEN_("Gen 1b") : "");
if (ismagic) if (ismagic)
snprintf(typestr + strlen(typestr), 4, " )"); snprintf(typestr + strlen(typestr), 4, " )");
@ -738,7 +747,7 @@ static int ulc_print_configuration(uint8_t *data) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t startPage) { static int ulev1_print_configuration(uint64_t tagtype, uint8_t *data, uint8_t startPage) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Configuration")); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Configuration"));
@ -756,7 +765,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
PrintAndLogEx(INFO, " cfg0 [%u/0x%02X]: %s", startPage, startPage, sprint_hex(data, 4)); PrintAndLogEx(INFO, " cfg0 [%u/0x%02X]: %s", startPage, startPage, sprint_hex(data, 4));
//NTAG213TT has different ASCII mirroring options and config bytes interpretation from other ulev1 class tags //NTAG213TT has different ASCII mirroring options and config bytes interpretation from other ulev1 class tags
if (tagtype & NTAG_213_TT) { if (tagtype & MFU_TT_NTAG_213_TT) {
uint8_t mirror_conf = ((data[0] & 0xE0) >> 5); uint8_t mirror_conf = ((data[0] & 0xE0) >> 5);
uint8_t mirror_byte = ((data[0] & 0x18) >> 3); uint8_t mirror_byte = ((data[0] & 0x18) >> 3);
uint8_t mirror_page = data[2]; uint8_t mirror_page = data[2];
@ -822,7 +831,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s", mirror_page, mirror_byte, (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("OK") : _YELLOW_("Invalid value")); PrintAndLogEx(INFO, " mirror start page %02X | byte pos %02X - %s", mirror_page, mirror_byte, (mirror_page >= 0x4 && ((mirror_user_mem_start_byte + bytes_required_for_mirror_data) <= 144)) ? _GREEN_("OK") : _YELLOW_("Invalid value"));
} }
} else if (tagtype & (NTAG_213_F | NTAG_216_F)) { } else if (tagtype & (MFU_TT_NTAG_213_F | MFU_TT_NTAG_216_F)) {
uint8_t mirror_conf = ((data[0] & 0xC0) >> 6); uint8_t mirror_conf = ((data[0] & 0xC0) >> 6);
uint8_t mirror_byte = (data[0] & 0x30); uint8_t mirror_byte = (data[0] & 0x30);
bool sleep_en = (data[0] & 0x08); bool sleep_en = (data[0] & 0x08);
@ -865,7 +874,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
break; break;
} }
// valid mirror start page and byte position within start page. // valid mirror start page and byte position within start page.
if (tagtype & NTAG_213_F) { if (tagtype & MFU_TT_NTAG_213_F) {
switch (mirror_conf) { switch (mirror_conf) {
case 1: case 1:
{ PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;}
@ -876,7 +885,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
default: default:
break; break;
} }
} else if (tagtype & NTAG_216_F) { } else if (tagtype & MFU_TT_NTAG_216_F) {
switch (mirror_conf) { switch (mirror_conf) {
case 1: case 1:
{ PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDE) ? "OK" : "Invalid value"); break;} { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0xDE) ? "OK" : "Invalid value"); break;}
@ -901,7 +910,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
uint8_t tt_msg_resp_len = 0; uint8_t tt_msg_resp_len = 0;
uint8_t tt_status_resp[5] = {0x00}; uint8_t tt_status_resp[5] = {0x00};
if (tagtype & NTAG_213_TT) { if (tagtype & MFU_TT_NTAG_213_TT) {
tt_enabled = (data[1] & 0x02); tt_enabled = (data[1] & 0x02);
tt_msg_resp_len = ul_read(45, tt_message, 4); tt_msg_resp_len = ul_read(45, tt_message, 4);
@ -941,7 +950,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
PrintAndLogEx(INFO, " PACK [%u/0x%02X]: %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2)); PrintAndLogEx(INFO, " PACK [%u/0x%02X]: %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 12, 2));
PrintAndLogEx(INFO, " RFU [%u/0x%02X]: %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2)); PrintAndLogEx(INFO, " RFU [%u/0x%02X]: %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data + 14, 2));
if (tagtype & NTAG_213_TT) { if (tagtype & MFU_TT_NTAG_213_TT) {
if (data[1] & 0x06) { if (data[1] & 0x06) {
PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s- (cannot be read)", sprint_hex(tt_message, tt_msg_resp_len)); PrintAndLogEx(INFO, "TT_MSG [45/0x2D]: %s- (cannot be read)", sprint_hex(tt_message, tt_msg_resp_len));
PrintAndLogEx(INFO, " - tamper message is masked in memory"); PrintAndLogEx(INFO, " - tamper message is masked in memory");
@ -952,7 +961,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
} }
//The NTAG213TT only returns meaningful information for the fields below if the tamper feature is enabled //The NTAG213TT only returns meaningful information for the fields below if the tamper feature is enabled
if ((tagtype & NTAG_213_TT) && tt_enabled) { if ((tagtype & MFU_TT_NTAG_213_TT) && tt_enabled) {
uint8_t tt_status_len = ntagtt_getTamperStatus(tt_status_resp, 5); uint8_t tt_status_len = ntagtt_getTamperStatus(tt_status_resp, 5);
@ -1012,9 +1021,10 @@ static int ulev1_print_counters(void) {
return len; return len;
} }
static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) { static int ulev1_print_signature(uint64_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len) {
#define PUBLIC_ECDA_KEYLEN 33 #define PUBLIC_ECDA_KEYLEN 33
#define PUBLIC_ECDA_192_KEYLEN 49
// known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier) // known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier)
// ref: AN11350 NTAG 21x Originality Signature Validation // ref: AN11350 NTAG 21x Originality Signature Validation
// ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation // ref: AN11341 MIFARE Ultralight EV1 Originality Signature Validation
@ -1028,6 +1038,11 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
{"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
}; };
// https://www.nxp.com/docs/en/application-note/AN13452.pdf
const ecdsa_publickey_t nxp_mfu_192_public_keys[] = {
{"NXP Ultralight AES", "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"},
};
/* /*
uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = { uint8_t nxp_mfu_public_keys[6][PUBLIC_ECDA_KEYLEN] = {
// UL, NTAG21x and NDEF // UL, NTAG21x and NDEF
@ -1076,6 +1091,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
*/ */
uint8_t i; uint8_t i;
bool is_valid = false; bool is_valid = false;
if (signature_len == 32) {
for (i = 0; i < ARRAYLEN(nxp_mfu_public_keys); i++) { for (i = 0; i < ARRAYLEN(nxp_mfu_public_keys); i++) {
int dl = 0; int dl = 0;
@ -1088,16 +1104,35 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
if (is_valid) if (is_valid)
break; break;
} }
}
bool is_192_valid = false;
if (signature_len == 48) {
for (i = 0; i < ARRAYLEN(nxp_mfu_192_public_keys); i++) {
int dl = 0;
uint8_t key[PUBLIC_ECDA_192_KEYLEN] = {0};
param_gethex_to_eol(nxp_mfu_192_public_keys[i].value, 0, key, PUBLIC_ECDA_192_KEYLEN, &dl);
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP192R1, key, uid, 7, signature, signature_len, false);
is_192_valid = (res == 0);
if (is_192_valid)
break;
}
}
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) { if (is_192_valid) {
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_192_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_192_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp192r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )"); PrintAndLogEx(SUCCESS, " Signature verification ( " _GREEN_("successful") " )");
return PM3_ESOFT; return PM3_SUCCESS;
} }
if (is_valid) {
PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_public_keys[i].desc); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_mfu_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value); PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
@ -1106,6 +1141,12 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
return PM3_SUCCESS; return PM3_SUCCESS;
} }
PrintAndLogEx(INFO, " Elliptic curve parameters: %s", (signature_len == 48) ? "NID_secp192r1" : "NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len));
PrintAndLogEx(SUCCESS, " Signature verification ( " _RED_("fail") " )");
return PM3_ESOFT;
}
static int ulev1_print_version(uint8_t *data) { static int ulev1_print_version(uint8_t *data) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Version")); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Version"));
@ -1152,14 +1193,14 @@ static int ulc_magic_test(){
uint8_t nonce1[11] = {0x00}; uint8_t nonce1[11] = {0x00};
uint8_t nonce2[11] = {0x00}; uint8_t nonce2[11] = {0x00};
if ( !ul_select(&card) ){ if ( !ul_select(&card) ){
return UL_ERROR; return MFU_TT_UL_ERROR;
} }
int status = ulc_requestAuthentication(nonce1, sizeof(nonce1)); int status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
if ( status > 0 ) { if ( status > 0 ) {
status = ulc_requestAuthentication(nonce2, sizeof(nonce2)); status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? MFU_TT_UL_C_MAGIC : MFU_TT_UL_C;
} else { } else {
returnValue = UL; returnValue = MFU_TT_UL;
} }
DropField(); DropField();
return returnValue; return returnValue;
@ -1172,12 +1213,12 @@ static int ul_magic_test(void) {
iso14a_card_select_t card; iso14a_card_select_t card;
if (ul_select(&card) == false) if (ul_select(&card) == false)
return UL_ERROR; return MFU_TT_UL_ERROR;
int status = ul_comp_write(0, NULL, 0); int status = ul_comp_write(0, NULL, 0);
DropField(); DropField();
if (status == 0) if (status == 0)
return MAGIC; return MFU_TT_MAGIC;
// check for GEN1A, GEN1B and NTAG21x // check for GEN1A, GEN1B and NTAG21x
uint8_t is_generation = 0; uint8_t is_generation = 0;
@ -1191,11 +1232,11 @@ static int ul_magic_test(void) {
} }
switch (is_generation) { switch (is_generation) {
case MAGIC_GEN_1A: case MAGIC_GEN_1A:
return MAGIC_1A; return MFU_TT_MAGIC_1A;
case MAGIC_GEN_1B: case MAGIC_GEN_1B:
return MAGIC_1B; return MFU_TT_MAGIC_1B;
case MAGIC_NTAG21X: case MAGIC_NTAG21X:
return MAGIC_NTAG; return MFU_TT_MAGIC_NTAG;
default: default:
break; break;
} }
@ -1461,7 +1502,7 @@ static int mfu_get_version_uid(uint8_t *version, uint8_t *uid) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authkey, int ak_len) { static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, uint8_t *authkey, int ak_len) {
uint8_t *data = NULL; uint8_t *data = NULL;
int res = PM3_SUCCESS; int res = PM3_SUCCESS;
@ -1486,7 +1527,7 @@ static int mfu_fingerprint(TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authke
uint8_t keytype = 0; uint8_t keytype = 0;
if (hasAuthKey) { if (hasAuthKey) {
if (tagtype & UL_C) if (tagtype & MFU_TT_UL_C)
keytype = 1; //UL_C auth keytype = 1; //UL_C auth
else else
keytype = 2; //UL_EV1/NTAG auth keytype = 2; //UL_EV1/NTAG auth
@ -1567,17 +1608,17 @@ out:
uint32_t GetHF14AMfU_Type(void) { uint32_t GetHF14AMfU_Type(void) {
TagTypeUL_t tagtype = UNKNOWN; uint64_t tagtype = MFU_TT_UNKNOWN;
iso14a_card_select_t card; iso14a_card_select_t card;
if (ul_select(&card) == false) if (ul_select(&card) == false)
return UL_ERROR; return MFU_TT_UL_ERROR;
// Ultralight - ATQA / SAK // Ultralight - ATQA / SAK
if (card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00) { if (card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00) {
//PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); //PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak);
DropField(); DropField();
return UL_ERROR; return MFU_TT_UL_ERROR;
} }
if (card.uid[0] != 0x05) { if (card.uid[0] != 0x05) {
@ -1628,79 +1669,80 @@ uint32_t GetHF14AMfU_Type(void) {
Feiju NTAG 0053040201000F03 Feiju NTAG 0053040201000F03
*/ */
if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; } if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { tagtype = MFU_TT_UL_EV1_48; break; }
else if (memcmp(version, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { tagtype = UL_NANO_40; break; } else if (memcmp(version, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { tagtype = MFU_TT_UL_NANO_40; break; }
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; } else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { tagtype = MFU_TT_UL_EV1_48; break; }
else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; }
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; }
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } // Mikron JSC Russia EV1 41 pages tag else if (memcmp(version, "\x00\x04\x03\x01\x04\x00\x0F\x03", 8) == 0) { tagtype = MFU_TT_UL_AES; break; }
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = NTAG_210; break; } else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_UL_EV1_128; break; } // Mikron JSC Russia EV1 41 pages tag
else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = NTAG_210u; break; } else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x02\x00\x0B", 7) == 0) { tagtype = NTAG_210u; break; } else if (memcmp(version, "\x00\x04\x04\x01\x02\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210u; break; }
else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; } else if (memcmp(version, "\x00\x04\x04\x02\x02\x00\x0B", 7) == 0) { tagtype = MFU_TT_NTAG_210u; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = MFU_TT_NTAG_212; break; }
else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } //Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter) else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; } else if (memcmp(version, "\x00\x53\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213; break; } // Shanghai Feiju Microelectronics Co. Ltd. China (Xiaomi Air Purifier filter)
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = NTAG_215; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x01\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213_C; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x11", 7) == 0) { tagtype = MFU_TT_NTAG_215; break; }
else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213_F; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = MFU_TT_NTAG_216; break; }
else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x13", 7) == 0) { tagtype = NTAG_216_F; break; } else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213_F; break; }
else if (memcmp(version, "\x00\x04\x04\x02\x03\x00\x0F", 7) == 0) { tagtype = NTAG_213_TT; break; } else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x13", 7) == 0) { tagtype = MFU_TT_NTAG_216_F; break; }
else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x13", 7) == 0) { tagtype = NTAG_I2C_1K; break; } else if (memcmp(version, "\x00\x04\x04\x02\x03\x00\x0F", 7) == 0) { tagtype = MFU_TT_NTAG_213_TT; break; }
else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x15", 7) == 0) { tagtype = NTAG_I2C_2K; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x13", 7) == 0) { tagtype = MFU_TT_NTAG_I2C_1K; break; }
else if (memcmp(version, "\x00\x04\x04\x05\x02\x02\x13", 7) == 0) { tagtype = NTAG_I2C_1K_PLUS; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x15", 7) == 0) { tagtype = MFU_TT_NTAG_I2C_2K; break; }
else if (memcmp(version, "\x00\x04\x04\x05\x02\x02\x15", 7) == 0) { tagtype = NTAG_I2C_2K_PLUS; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x02\x13", 7) == 0) { tagtype = MFU_TT_NTAG_I2C_1K_PLUS; break; }
else if (version[2] == 0x04) { tagtype = NTAG; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x02\x15", 7) == 0) { tagtype = MFU_TT_NTAG_I2C_2K_PLUS; break; }
else if (version[2] == 0x03) { tagtype = UL_EV1; } else if (version[2] == 0x04) { tagtype = MFU_TT_NTAG; break; }
else if (version[2] == 0x03) { tagtype = MFU_TT_UL_EV1; }
break; break;
} }
case 0x01: case 0x01:
tagtype = UL_C; tagtype = MFU_TT_UL_C;
break; break;
case 0x00: case 0x00:
tagtype = UL; tagtype = MFU_TT_UL;
break; break;
case -1 : case -1 :
tagtype = (UL | UL_C | NTAG_203); tagtype = (MFU_TT_UL | MFU_TT_UL_C | MFU_TT_NTAG_203);
break; // could be UL | UL_C magic tags break; // could be UL | UL_C magic tags
default : default :
tagtype = UNKNOWN; tagtype = MFU_TT_UNKNOWN;
break; break;
} }
// UL vs UL-C vs ntag203 test // UL vs UL-C vs ntag203 test
if (tagtype & (UL | UL_C | NTAG_203)) { if (tagtype & (MFU_TT_UL | MFU_TT_UL_C | MFU_TT_NTAG_203)) {
if (!ul_select(&card)) return UL_ERROR; if (!ul_select(&card)) return MFU_TT_UL_ERROR;
// do UL_C check first... // do UL_C check first...
uint8_t nonce[11] = {0x00}; uint8_t nonce[11] = {0x00};
int status = ulc_requestAuthentication(nonce, sizeof(nonce)); int status = ulc_requestAuthentication(nonce, sizeof(nonce));
DropField(); DropField();
if (status > 1) { if (status > 1) {
tagtype = UL_C; tagtype = MFU_TT_UL_C;
} else { } else {
// need to re-select after authentication error // need to re-select after authentication error
if (ul_select(&card) == false) if (ul_select(&card) == false)
return UL_ERROR; return MFU_TT_UL_ERROR;
uint8_t data[16] = {0x00}; uint8_t data[16] = {0x00};
// read page 0x26-0x29 (last valid ntag203 page) // read page 0x26-0x29 (last valid ntag203 page)
status = ul_read(0x26, data, sizeof(data)); status = ul_read(0x26, data, sizeof(data));
if (status <= 1) { if (status <= 1) {
tagtype = UL; tagtype = MFU_TT_UL;
} else { } else {
// read page 0x30 (should error if it is a ntag203) // read page 0x30 (should error if it is a ntag203)
status = ul_read(0x30, data, sizeof(data)); status = ul_read(0x30, data, sizeof(data));
if (status <= 1) { if (status <= 1) {
tagtype = NTAG_203; tagtype = MFU_TT_NTAG_203;
} else { } else {
tagtype = UNKNOWN; tagtype = MFU_TT_UNKNOWN;
} }
} }
DropField(); DropField();
} }
} }
if (tagtype & UL) { if (tagtype & MFU_TT_UL) {
tagtype = ul_fudan_check(); tagtype = ul_fudan_check();
DropField(); DropField();
} }
@ -1711,23 +1753,23 @@ uint32_t GetHF14AMfU_Type(void) {
switch (nib) { switch (nib) {
// case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k
case 1: case 1:
tagtype = MY_D; tagtype = MFU_TT_MY_D;
break; // or SLE 66RxxS ... up to 512 pages of 8 user bytes... break; // or SLE 66RxxS ... up to 512 pages of 8 user bytes...
case 2: case 2:
tagtype = (MY_D_NFC); tagtype = MFU_TT_MY_D_NFC;
break; // or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) break; // or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes)
case 3: case 3:
tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); tagtype = (MFU_TT_MY_D_MOVE | MFU_TT_MY_D_MOVE_NFC);
break; // or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two break; // or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two
case 7: case 7:
tagtype = MY_D_MOVE_LEAN; tagtype = MFU_TT_MY_D_MOVE_LEAN;
break; // or SLE 66R01L // 16 pages of 4 bytes break; // or SLE 66R01L // 16 pages of 4 bytes
} }
} }
tagtype |= ul_magic_test(); tagtype |= ul_magic_test();
if (tagtype == (UNKNOWN | MAGIC)) { if (tagtype == (MFU_TT_UNKNOWN | MFU_TT_MAGIC)) {
tagtype = (UL_MAGIC); tagtype = (MFU_TT_UL_MAGIC);
} }
return tagtype; return tagtype;
} }
@ -1780,8 +1822,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
uint8_t pack[4] = {0, 0, 0, 0}; uint8_t pack[4] = {0, 0, 0, 0};
int len; int len;
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) if (tagtype == MFU_TT_UL_ERROR)
return PM3_ESOFT; return PM3_ESOFT;
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -1812,7 +1854,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
} }
// UL_C Specific // UL_C Specific
if ((tagtype & UL_C)) { if ((tagtype & MFU_TT_UL_C)) {
// read pages 0x28, 0x29, 0x2A, 0x2B // read pages 0x28, 0x29, 0x2A, 0x2B
uint8_t ulc_conf[16] = {0x00}; uint8_t ulc_conf[16] = {0x00};
@ -1829,7 +1871,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len); mfu_fingerprint(tagtype, has_auth_key, authkeyptr, ak_len);
if ((tagtype & MAGIC)) { if ((tagtype & MFU_TT_MAGIC)) {
//just read key //just read key
uint8_t ulc_deskey[16] = {0x00}; uint8_t ulc_deskey[16] = {0x00};
status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey));
@ -1863,7 +1905,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
// do counters and signature first (don't neet auth) // do counters and signature first (don't neet auth)
// ul counters are different than ntag counters // ul counters are different than ntag counters
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1))) { if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1))) {
if (ulev1_print_counters() != 3) { if (ulev1_print_counters() != 3) {
// failed - re-select // failed - re-select
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
@ -1873,7 +1915,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
} }
// NTAG counters? // NTAG counters?
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) { if ((tagtype & (MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216))) {
if (ntag_print_counter()) { if (ntag_print_counter()) {
// failed - re-select // failed - re-select
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
@ -1883,8 +1925,12 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
} }
// Read signature // Read signature
if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_210u | NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) { if ((tagtype & (MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1 | MFU_TT_UL_NANO_40 |
uint8_t ulev1_signature[32] = {0x00}; MFU_TT_NTAG_210u | MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C |
MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216 | MFU_TT_NTAG_216_F |
MFU_TT_NTAG_I2C_1K | MFU_TT_NTAG_I2C_2K | MFU_TT_NTAG_I2C_1K_PLUS | MFU_TT_NTAG_I2C_2K_PLUS |
MFU_TT_UL_AES))) {
uint8_t ulev1_signature[49] = {0x00};
status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature));
if (status == -1) { if (status == -1) {
PrintAndLogEx(ERR, "Error: tag didn't answer to READ SIGNATURE"); PrintAndLogEx(ERR, "Error: tag didn't answer to READ SIGNATURE");
@ -1892,7 +1938,9 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
if (status == 32) { if (status == 32) {
ulev1_print_signature(tagtype, card.uid, ulev1_signature, sizeof(ulev1_signature)); ulev1_print_signature(tagtype, card.uid, ulev1_signature, 32);
} else if (status == 48) {
ulev1_print_signature(tagtype, card.uid, ulev1_signature, 48);
} else { } else {
// re-select // re-select
if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) { if (ul_auth_select(&card, tagtype, has_auth_key, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) {
@ -2096,8 +2144,8 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
uint8_t *authKeyPtr = authenticationkey; uint8_t *authKeyPtr = authenticationkey;
// starting with getting tagtype // starting with getting tagtype
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) if (tagtype == MFU_TT_UL_ERROR)
return PM3_ESOFT; return PM3_ESOFT;
uint8_t maxblockno = 0; uint8_t maxblockno = 0;
@ -2217,8 +2265,8 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
uint8_t *authKeyPtr = authenticationkey; uint8_t *authKeyPtr = authenticationkey;
// start with getting tagtype // start with getting tagtype
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) if (tagtype == MFU_TT_UL_ERROR)
return PM3_ESOFT; return PM3_ESOFT;
uint8_t maxblockno = 0; uint8_t maxblockno = 0;
@ -2328,7 +2376,12 @@ void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage) {
for (uint16_t i = 0; i < pages; ++i) { for (uint16_t i = 0; i < pages; ++i) {
if (i < 3) { if (i < 3) {
PrintAndLogEx(INFO, "%3d/0x%02X | %s| | %s", i + startpage, i + startpage, sprint_hex(data + i * 4, 4), sprint_ascii(data + i * 4, 4)); PrintAndLogEx(INFO, "%3d/0x%02X | " _RED_("%s")"| | %s",
i + startpage,
i + startpage,
sprint_hex(data + i * 4, 4),
sprint_ascii(data + i * 4, 4)
);
continue; continue;
} }
switch (i) { switch (i) {
@ -2434,7 +2487,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu dump", CLIParserInit(&ctx, "hf mfu dump",
"Dump MIFARE Ultralight/NTAG tag to binary/eml/json files.\n" "Dump MIFARE Ultralight/NTAG tag to files (bin/json)\n"
"It autodetects card type." "It autodetects card type."
"Supports:\n" "Supports:\n"
"Ultralight, Ultralight-C, Ultralight EV1\n" "Ultralight, Ultralight-C, Ultralight EV1\n"
@ -2501,8 +2554,8 @@ static int CmdHF14AMfUDump(const char *Cmd) {
authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4); authKeyPtr = SwapEndian64(authenticationkey, ak_len, 4);
} }
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) if (tagtype == MFU_TT_UL_ERROR)
return PM3_ESOFT; return PM3_ESOFT;
//get number of pages to read //get number of pages to read
@ -2519,7 +2572,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Reading tag memory..."); PrintAndLogEx(SUCCESS, "Reading tag memory...");
uint8_t keytype = 0; uint8_t keytype = 0;
if (has_auth_key || has_pwd) { if (has_auth_key || has_pwd) {
if (tagtype & UL_C) if (tagtype & MFU_TT_UL_C)
keytype = 1; //UL_C auth keytype = 1; //UL_C auth
else else
keytype = 2; //UL_EV1/NTAG auth keytype = 2; //UL_EV1/NTAG auth
@ -2569,7 +2622,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
// not ul_c and not std ul then attempt to collect info like // not ul_c and not std ul then attempt to collect info like
// VERSION, SIGNATURE, COUNTERS, TEARING, PACK, // VERSION, SIGNATURE, COUNTERS, TEARING, PACK,
if (!(tagtype & UL_C || tagtype & UL || tagtype & MY_D_MOVE || tagtype & MY_D_MOVE_LEAN)) { if (!(tagtype & MFU_TT_UL_C || tagtype & MFU_TT_UL || tagtype & MFU_TT_MY_D_MOVE || tagtype & MFU_TT_MY_D_MOVE_LEAN)) {
//attempt to read pack //attempt to read pack
uint8_t get_pack[] = {0, 0}; uint8_t get_pack[] = {0, 0};
if (ul_auth_select(&card, tagtype, true, authKeyPtr, get_pack, sizeof(get_pack)) != PM3_SUCCESS) { if (ul_auth_select(&card, tagtype, true, authKeyPtr, get_pack, sizeof(get_pack)) != PM3_SUCCESS) {
@ -2599,7 +2652,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
uint8_t n = 0; uint8_t n = 0;
// NTAG has 1 counter, at 0x02 // NTAG has 1 counter, at 0x02
if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_C | NTAG_213_TT | NTAG_215 | NTAG_216))) { if ((tagtype & (MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216))) {
n = 2; n = 2;
} }
@ -2647,7 +2700,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
authKeyPtr = authenticationkey; authKeyPtr = authenticationkey;
} }
if (tagtype & UL_C) { //add 4 pages if (tagtype & MFU_TT_UL_C) { //add 4 pages
memcpy(data + pages * 4, authKeyPtr, ak_len); memcpy(data + pages * 4, authKeyPtr, ak_len);
pages += ak_len / 4; pages += ak_len / 4;
} else { // 2nd page from end } else { // 2nd page from end
@ -2665,7 +2718,12 @@ static int CmdHF14AMfUDump(const char *Cmd) {
printMFUdumpEx(&dump_file_data, pages, start_page); printMFUdumpEx(&dump_file_data, pages, start_page);
if (nosave == false) { if (nosave) {
PrintAndLogEx(INFO, "Called with no save option");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
// user supplied filename? // user supplied filename?
if (fnlen < 1) { if (fnlen < 1) {
PrintAndLogEx(INFO, "Using UID as filename"); PrintAndLogEx(INFO, "Using UID as filename");
@ -2677,12 +2735,11 @@ static int CmdHF14AMfUDump(const char *Cmd) {
} }
uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory);
if (is_partial) { if (is_partial) {
PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size); PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
} }
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2742,13 +2799,13 @@ int CmdHF14MfUTamper(const char *Cmd) {
bool disable = arg_get_lit(ctx, 2); bool disable = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) { if (tagtype == MFU_TT_UL_ERROR) {
PrintAndLogEx(WARNING, "Tag type not detected"); PrintAndLogEx(WARNING, "Tag type not detected");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
} }
if (tagtype != NTAG_213_TT) { if (tagtype != MFU_TT_NTAG_213_TT) {
PrintAndLogEx(WARNING, "Tag type not NTAG 213TT"); PrintAndLogEx(WARNING, "Tag type not NTAG 213TT");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -2766,7 +2823,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
if (use_msg) { if (use_msg) {
if (ul_select(&card) == false) { if (ul_select(&card) == false) {
DropField(); DropField();
return UL_ERROR; return MFU_TT_UL_ERROR;
} }
PrintAndLogEx(INFO, "Trying to write tamper message\n"); PrintAndLogEx(INFO, "Trying to write tamper message\n");
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, tt_msg_page, 0, 0, msg_data, 4);
@ -2789,7 +2846,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
if (ul_select(&card) == false) { if (ul_select(&card) == false) {
PrintAndLogEx(ERR, "Unable to select tag"); PrintAndLogEx(ERR, "Unable to select tag");
DropField(); DropField();
return UL_ERROR; return MFU_TT_UL_ERROR;
} }
uint8_t cfg_page[4] = {0x00}; uint8_t cfg_page[4] = {0x00};
@ -2840,7 +2897,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
static int CmdHF14AMfURestore(const char *Cmd) { static int CmdHF14AMfURestore(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu restore", CLIParserInit(&ctx, "hf mfu restore",
"Restore MIFARE Ultralight/NTAG dump file to tag.\n", "Restore MIFARE Ultralight/NTAG dump file (bin/eml/json) to tag.\n",
"hf mfu restore -f myfile -s -> special write\n" "hf mfu restore -f myfile -s -> special write\n"
"hf mfu restore -f myfile -k AABBCCDD -s -> special write, use key\n" "hf mfu restore -f myfile -k AABBCCDD -s -> special write, use key\n"
"hf mfu restore -f myfile -k AABBCCDD -ser -> special write, use key, write dump pwd, ..." "hf mfu restore -f myfile -k AABBCCDD -ser -> special write, use key, write dump pwd, ..."
@ -2848,7 +2905,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "specify dump filename (bin/eml/json)"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"), arg_str0("k", "key", "<hex>", "key for authentication (UL-C 16 bytes, EV1/NTAG 4 bytes)"),
arg_lit0("l", NULL, "swap entered key's endianness"), arg_lit0("l", NULL, "swap entered key's endianness"),
arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"), arg_lit0("s", NULL, "enable special write UID -MAGIC TAG ONLY-"),
@ -3065,7 +3122,7 @@ static int CmdHF14AMfUeLoad(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "Filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_int0("q", "qty", "<dec>", "Number of blocks to load from eml file"), arg_int0("q", "qty", "<dec>", "Number of blocks to load from eml file"),
arg_lit0("v", "verbose", "verbose output"), arg_lit0("v", "verbose", "verbose output"),
arg_param_end arg_param_end
@ -4375,8 +4432,8 @@ int CmdHF14MfuNDEFRead(const char *Cmd) {
} }
// Get tag type // Get tag type
TagTypeUL_t tagtype = GetHF14AMfU_Type(); uint64_t tagtype = GetHF14AMfU_Type();
if (tagtype == UL_ERROR) { if (tagtype == MFU_TT_UL_ERROR) {
PrintAndLogEx(WARNING, "No Ultralight / NTAG based tag found"); PrintAndLogEx(WARNING, "No Ultralight / NTAG based tag found");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -4443,14 +4500,20 @@ int CmdHF14MfuNDEFRead(const char *Cmd) {
} }
DropField(); DropField();
if (fnlen != 0) {
saveFile(filename, ".bin", records, (size_t)maxsize);
}
status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize, verbose); status = NDEFRecordsDecodeAndPrint(records, (size_t)maxsize, verbose);
if (status != PM3_SUCCESS) { if (status != PM3_SUCCESS) {
status = NDEFDecodeAndPrint(records, (size_t)maxsize, verbose); status = NDEFDecodeAndPrint(records, (size_t)maxsize, verbose);
} }
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(records, maxsize, &n) != PM3_SUCCESS)
n = maxsize;
pm3_save_dump(filename, records, n, jsfNDEF);
char *jooki = strstr((char *)records, "s.jooki.rocks/s/?s="); char *jooki = strstr((char *)records, "s.jooki.rocks/s/?s=");
if (jooki) { if (jooki) {
jooki += 17; jooki += 17;
@ -4557,18 +4620,18 @@ static int CmdHF14AMfuEView(const char *Cmd) {
static int CmdHF14AMfuESave(const char *Cmd) { static int CmdHF14AMfuESave(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu esave", CLIParserInit(&ctx, "hf mfu esave",
"Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/eml/json)\n" "Saves emulator memory to a MIFARE Ultralight/NTAG dump file (bin/json)\n"
"By default number of pages saved depends on defined tag type.\n" "By default number of pages saved depends on defined tag type.\n"
"You can override this with option --end.", "You can override this with option --end.",
"hf mfu esave\n" "hf mfu esave\n"
"hf mfu esave --end 255 -> saves whole memory\n" "hf mfu esave --end 255 -> saves whole memory\n"
"hf mfu esave -f hf-mfu-04010203040506-dump.json" "hf mfu esave -f hf-mfu-04010203040506-dump"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int0("e", "end", "<dec>", "index of last block"), arg_int0("e", "end", "<dec>", "index of last block"),
arg_str0("f", "file", "<fn>", "filename of dump"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
@ -4613,7 +4676,7 @@ static int CmdHF14AMfuESave(const char *Cmd) {
// save dump. Last block contains PACK + RFU // save dump. Last block contains PACK + RFU
uint16_t datalen = (end + 1) * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH; uint16_t datalen = (end + 1) * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory, MFU_BLOCK_SIZE); res = pm3_save_dump(filename, (uint8_t *)dump, datalen, jsfMfuMemory);
free(dump); free(dump);
return res; return res;
@ -4628,7 +4691,7 @@ static int CmdHF14AMfuView(const char *Cmd) {
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "Filename of dump"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_lit0("v", "verbose", "Verbose output"), arg_lit0("v", "verbose", "Verbose output"),
arg_param_end arg_param_end
}; };

View file

@ -43,7 +43,7 @@ typedef struct {
} PACKED old_mfu_dump_t; } PACKED old_mfu_dump_t;
uint32_t GetHF14AMfU_Type(void); uint32_t GetHF14AMfU_Type(void);
int ul_print_type(uint32_t tagtype, uint8_t spaces); int ul_print_type(uint64_t tagtype, uint8_t spaces);
void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage); void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage);
int ul_read_uid(uint8_t *uid); int ul_read_uid(uint8_t *uid);
int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]); int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]);
@ -55,44 +55,44 @@ int CmdHF14MfUTamper(const char *Cmd);
uint16_t ul_ev1_packgen_VCNEW(uint8_t *uid, uint32_t pwd); uint16_t ul_ev1_packgen_VCNEW(uint8_t *uid, uint32_t pwd);
uint32_t ul_ev1_otpgenA(uint8_t *uid); uint32_t ul_ev1_otpgenA(uint8_t *uid);
typedef enum TAGTYPE_UL { #define MFU_TT_UNKNOWN 0x0ULL
UNKNOWN = 0x000000, #define MFU_TT_UL 0x1ULL
UL = 0x1, #define MFU_TT_UL_C 0x2ULL
UL_C = 0x2, #define MFU_TT_UL_EV1_48 0x4ULL
UL_EV1_48 = 0x4, #define MFU_TT_UL_EV1_128 0x8ULL
UL_EV1_128 = 0x8, #define MFU_TT_NTAG 0x10ULL
NTAG = 0x10, #define MFU_TT_NTAG_203 0x20ULL
NTAG_203 = 0x20, #define MFU_TT_NTAG_210 0x40ULL
NTAG_210 = 0x40, #define MFU_TT_NTAG_212 0x80ULL
NTAG_212 = 0x80, #define MFU_TT_NTAG_213 0x100ULL
NTAG_213 = 0x100, #define MFU_TT_NTAG_215 0x200ULL
NTAG_215 = 0x200, #define MFU_TT_NTAG_216 0x400ULL
NTAG_216 = 0x400, #define MFU_TT_MY_D 0x800ULL
MY_D = 0x800, #define MFU_TT_MY_D_NFC 0x1000ULL
MY_D_NFC = 0x1000, #define MFU_TT_MY_D_MOVE 0x2000ULL
MY_D_MOVE = 0x2000, #define MFU_TT_MY_D_MOVE_NFC 0x4000ULL
MY_D_MOVE_NFC = 0x4000, #define MFU_TT_MY_D_MOVE_LEAN 0x8000ULL
MY_D_MOVE_LEAN = 0x8000, #define MFU_TT_NTAG_I2C_1K 0x10000ULL
NTAG_I2C_1K = 0x10000, #define MFU_TT_NTAG_I2C_2K 0x20000ULL
NTAG_I2C_2K = 0x20000, #define MFU_TT_NTAG_I2C_1K_PLUS 0x40000ULL
NTAG_I2C_1K_PLUS = 0x40000, #define MFU_TT_NTAG_I2C_2K_PLUS 0x80000ULL
NTAG_I2C_2K_PLUS = 0x80000, #define MFU_TT_FUDAN_UL 0x100000ULL
FUDAN_UL = 0x100000, #define MFU_TT_MAGIC 0x200000ULL
MAGIC = 0x200000, #define MFU_TT_NTAG_213_F 0x400000ULL
NTAG_213_F = 0x400000, #define MFU_TT_NTAG_216_F 0x800000ULL
NTAG_216_F = 0x800000, #define MFU_TT_UL_EV1 0x1000000ULL
UL_EV1 = 0x1000000, #define MFU_TT_UL_NANO_40 0x2000000ULL
UL_NANO_40 = 0x2000000, #define MFU_TT_NTAG_213_TT 0x4000000ULL
NTAG_213_TT = 0x4000000, #define MFU_TT_NTAG_213_C 0x8000000ULL
NTAG_213_C = 0x8000000, #define MFU_TT_MAGIC_1A (0x10000000ULL | MFU_TT_MAGIC)
MAGIC_1A = 0x10000000 | MAGIC, #define MFU_TT_MAGIC_1B (0x20000000ULL | MFU_TT_MAGIC)
MAGIC_1B = 0x20000000 | MAGIC, #define MFU_TT_MAGIC_NTAG (0x40000000ULL | MFU_TT_MAGIC)
MAGIC_NTAG = 0x40000000 | MAGIC, #define MFU_TT_NTAG_210u 0x80000000ULL
NTAG_210u = 0x80000000, #define MFU_TT_UL_AES 0x100000000ULL
UL_MAGIC = UL | MAGIC, #define MFU_TT_UL_MAGIC (MFU_TT_UL | MFU_TT_MAGIC)
UL_C_MAGIC = UL_C | MAGIC, #define MFU_TT_UL_C_MAGIC (MFU_TT_UL_C | MFU_TT_MAGIC)
// Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added // Don't forget to fill UL_TYPES_ARRAY and UL_MEMORY_ARRAY if new types are added
UL_ERROR = 0xFFFFFF, #define MFU_TT_UL_ERROR 0x7FFFFFFFULL
} TagTypeUL_t;
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -404,10 +404,15 @@ int CmdHFST25TANdefRead(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
if (fnlen != 0) {
saveFile(filename, ".bin", response + 2, resplen - 4);
}
NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose); NDEFRecordsDecodeAndPrint(response + 2, resplen - 4, verbose);
// get total NDEF length before save. If fails, we save it all
size_t n = 0;
if (NDEFGetTotalLength(response, resplen, &n) != PM3_SUCCESS)
n = resplen;
pm3_save_dump(filename, response + 2, n, jsfNDEF);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -429,7 +429,7 @@ static void TexcomReverseCode(const uint8_t *code, int length, uint8_t *reverse_
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
reverse_code[i] = code[(length - 1) - i]; reverse_code[i] = code[(length - 1) - i];
} }
}; }
static int texkom_get_type(texkom_card_select_t *card, bool verbose) { static int texkom_get_type(texkom_card_select_t *card, bool verbose) {
@ -493,7 +493,7 @@ static int texkom_get_type(texkom_card_select_t *card, bool verbose) {
noiselvl = TEXKOM_NOISE_THRESHOLD; noiselvl = TEXKOM_NOISE_THRESHOLD;
} }
uint32_t implengths[256] = {}; uint32_t implengths[256] = { 0 };
uint32_t implengthslen = 0; uint32_t implengthslen = 0;
uint32_t impulseindx = 0; uint32_t impulseindx = 0;
uint32_t impulsecnt = 0; uint32_t impulsecnt = 0;
@ -707,7 +707,7 @@ static int CmdHFTexkomReader(const char *Cmd) {
//PrintAndLogEx(WARNING, "--- indx: %d, len: %d, max: %d, noise: %d", sindx, slen, maxlvl, noiselvl); //PrintAndLogEx(WARNING, "--- indx: %d, len: %d, max: %d, noise: %d", sindx, slen, maxlvl, noiselvl);
uint32_t implengths[256] = {}; uint32_t implengths[256] = { 0 };
uint32_t implengthslen = 0; uint32_t implengthslen = 0;
uint32_t impulseindx = 0; uint32_t impulseindx = 0;
uint32_t impulsecnt = 0; uint32_t impulsecnt = 0;
@ -872,7 +872,7 @@ static int CmdHFTexkomSim(const char *Cmd) {
uint8_t data[8]; uint8_t data[8];
uint8_t modulation; uint8_t modulation;
uint32_t timeout; uint32_t timeout;
} PACKED payload = {}; } PACKED payload = {0};
bool verbose = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 1);
payload.modulation = 0; // tk-13 payload.modulation = 0; // tk-13

View file

@ -838,13 +838,13 @@ static int CmdHFTopazDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz dump", CLIParserInit(&ctx, "hf topaz dump",
"Dump TOPAZ tag to binary file\n" "Dump TOPAZ tag to file (bin/json)\n"
"If no <name> given, UID will be used as filename", "If no <name> given, UID will be used as filename",
"hf topaz dump\n"); "hf topaz dump\n");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_lit0(NULL, "ns", "no save to file"), arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
@ -897,9 +897,9 @@ static int CmdHFTopazDump(const char *Cmd) {
} }
if (topaz_tag.size) if (topaz_tag.size)
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz, TOPAZ_BLOCK_SIZE); pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t) + topaz_tag.size, jsfTopaz);
else else
pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz, TOPAZ_BLOCK_SIZE); pm3_save_dump(filename, (uint8_t *)&topaz_tag, sizeof(topaz_tag_t), jsfTopaz);
if (set_dynamic) { if (set_dynamic) {
free(topaz_tag.dynamic_memory); free(topaz_tag.dynamic_memory);
@ -916,7 +916,7 @@ static int CmdHFTopazView(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "filename of dump (bin/eml/json)"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -356,7 +356,7 @@ static int VASReader(uint8_t *pidHash, const char *url, size_t urlLen, uint8_t *
}; };
if (SelectCard14443A_4_WithParameters(false, false, NULL, &polling_parameters) != PM3_SUCCESS) { if (SelectCard14443A_4_WithParameters(false, false, NULL, &polling_parameters) != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "No card in field"); PrintAndLogEx(WARNING, "No ISO14443-A Card in field");
return PM3_ECARDEXCHANGE; return PM3_ECARDEXCHANGE;
} }
@ -586,10 +586,10 @@ static command_t CommandTable[] = {
int CmdHFVAS(const char *Cmd) { int CmdHFVAS(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
}; }
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return PM3_SUCCESS; return PM3_SUCCESS;
}; }

View file

@ -611,9 +611,7 @@ static int CmdHFXeroxDump(const char *Cmd) {
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool decrypt = arg_get_lit(ctx, 2); bool decrypt = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11); iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
@ -682,7 +680,6 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(NORMAL, "." NOLF); PrintAndLogEx(NORMAL, "." NOLF);
fflush(stdout); fflush(stdout);
// PrintAndLogEx(INPLACE, "blk %3d", blocknum);
} }
} }
@ -773,23 +770,13 @@ static int CmdHFXeroxDump(const char *Cmd) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (0 == filename[0]) { // generate filename from uid if (0 == filename[0]) { // generate filename from uid
/*
PrintAndLogEx(INFO, "Using UID as filename");
sprintf(filename, "hf-xerox-%02X%02X%02X%02X%02X%02X%02X%02X-dump%s",
card.uid[7],card.uid[6],card.uid[5],card.uid[4],card.uid[3],card.uid[2],card.uid[1],card.uid[0],
decrypt ? "-dec" : "");
*/
char *fptr = filename; char *fptr = filename;
PrintAndLogEx(INFO, "Using UID as filename"); PrintAndLogEx(INFO, "Using UID as filename");
fptr += snprintf(fptr, sizeof(filename), "hf-xerox-"); fptr += snprintf(fptr, sizeof(filename), "hf-xerox-");
FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen); FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), decrypt ? "-dump-dec" : "-dump", card.uidlen);
} }
size_t datalen = blocknum * 4; pm3_save_dump(filename, data, blocknum * 4, jsf14b_v2);
saveFile(filename, ".bin", data, datalen);
saveFileEML(filename, data, datalen, 4);
// saveFileJSON(filename, jsf15, data, datalen, NULL);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -35,6 +35,7 @@
#include "pmflash.h" // rdv40validation_t #include "pmflash.h" // rdv40validation_t
#include "cmdflashmem.h" // get_signature.. #include "cmdflashmem.h" // get_signature..
#include "uart/uart.h" // configure timeout #include "uart/uart.h" // configure timeout
#include "util_posix.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -44,6 +45,7 @@ static void lookup_chipid_short(uint32_t iChipID, uint32_t mem_used) {
case 0x270B0A40: case 0x270B0A40:
asBuff = "AT91SAM7S512 Rev A"; asBuff = "AT91SAM7S512 Rev A";
break; break;
case 0x270B0A4E:
case 0x270B0A4F: case 0x270B0A4F:
asBuff = "AT91SAM7S512 Rev B"; asBuff = "AT91SAM7S512 Rev B";
break; break;
@ -152,6 +154,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
case 0x270B0A40: case 0x270B0A40:
asBuff = "AT91SAM7S512 Rev A"; asBuff = "AT91SAM7S512 Rev A";
break; break;
case 0x270B0A4E:
case 0x270B0A4F: case 0x270B0A4F:
asBuff = "AT91SAM7S512 Rev B"; asBuff = "AT91SAM7S512 Rev B";
break; break;
@ -809,19 +812,29 @@ static int CmdStatus(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hw status", CLIParserInit(&ctx, "hw status",
"Show runtime status information about the connected Proxmark3", "Show runtime status information about the connected Proxmark3",
"hw status" "hw status\n"
"hw status --ms 1000 -> Test connection speed with 1000ms timeout\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int0("m", "ms", "<ms>", "speed test timeout in micro seconds"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
int32_t speedTestTimeout = arg_get_int_def(ctx, 1, -1);
CLIParserFree(ctx); CLIParserFree(ctx);
clearCommandBuffer(); clearCommandBuffer();
PacketResponseNG resp; PacketResponseNG resp;
if (speedTestTimeout < 0) {
speedTestTimeout = 0;
SendCommandNG(CMD_STATUS, NULL, 0); SendCommandNG(CMD_STATUS, NULL, 0);
if (WaitForResponseTimeout(CMD_STATUS, &resp, 2000) == false) { } else {
SendCommandNG(CMD_STATUS, (uint8_t *)&speedTestTimeout, sizeof(speedTestTimeout));
}
if (WaitForResponseTimeout(CMD_STATUS, &resp, 2000 + speedTestTimeout) == false) {
PrintAndLogEx(WARNING, "Status command timeout. Communication speed test timed out"); PrintAndLogEx(WARNING, "Status command timeout. Communication speed test timed out");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
@ -932,13 +945,13 @@ static int CmdTimeout(const char *Cmd) {
CLIParserInit(&ctx, "hw timeout", CLIParserInit(&ctx, "hw timeout",
"Set the communication timeout on the client side", "Set the communication timeout on the client side",
"hw timeout --> Show current timeout\n" "hw timeout --> Show current timeout\n"
"hw timeout -t 20 --> Set the timeout to 20ms\n" "hw timeout -m 20 --> Set the timeout to 20ms\n"
"hw timeout -t 500 --> Set the timeout to 500ms\n" "hw timeout --ms 500 --> Set the timeout to 500ms\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_int0("t", "timeout", "<dec>", "timeout in ms"), arg_int0("m", "ms", "<ms>", "timeout in micro seconds"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -949,7 +962,7 @@ static int CmdTimeout(const char *Cmd) {
// timeout is not given/invalid, just show the current timeout then return // timeout is not given/invalid, just show the current timeout then return
if (arg < 0) { if (arg < 0) {
PrintAndLogEx(INFO, "Current communication timeout: %ums", oldTimeout); PrintAndLogEx(INFO, "Current communication timeout... " _GREEN_("%u") " ms", oldTimeout);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -961,8 +974,8 @@ static int CmdTimeout(const char *Cmd) {
PrintAndLogEx(WARNING, "Timeout greater than 5000 ms makes the client unresponsive."); PrintAndLogEx(WARNING, "Timeout greater than 5000 ms makes the client unresponsive.");
} }
uart_reconfigure_timeouts(newTimeout); uart_reconfigure_timeouts(newTimeout);
PrintAndLogEx(INFO, "Old communication timeout: %ums", oldTimeout); PrintAndLogEx(INFO, "Old communication timeout... %u ms", oldTimeout);
PrintAndLogEx(INFO, "New communication timeout: %ums", newTimeout); PrintAndLogEx(INFO, "New communication timeout... " _GREEN_("%u") " ms", newTimeout);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -979,6 +992,7 @@ static int CmdPing(const char *Cmd) {
arg_u64_0("l", "len", "<dec>", "length of payload to send"), arg_u64_0("l", "len", "<dec>", "length of payload to send"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
uint32_t len = arg_get_u32_def(ctx, 1, 32); uint32_t len = arg_get_u32_def(ctx, 1, 32);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -987,7 +1001,7 @@ static int CmdPing(const char *Cmd) {
len = PM3_CMD_DATA_SIZE; len = PM3_CMD_DATA_SIZE;
if (len) { if (len) {
PrintAndLogEx(INFO, "Ping sent with payload len " _YELLOW_("%d"), len); PrintAndLogEx(INFO, "Ping sent with payload len... " _YELLOW_("%d"), len);
} else { } else {
PrintAndLogEx(INFO, "Ping sent"); PrintAndLogEx(INFO, "Ping sent");
} }
@ -996,16 +1010,22 @@ static int CmdPing(const char *Cmd) {
PacketResponseNG resp; PacketResponseNG resp;
uint8_t data[PM3_CMD_DATA_SIZE] = {0}; uint8_t data[PM3_CMD_DATA_SIZE] = {0};
for (uint16_t i = 0; i < len; i++) for (uint16_t i = 0; i < len; i++) {
data[i] = i & 0xFF; data[i] = i & 0xFF;
}
uint64_t tms = msclock();
SendCommandNG(CMD_PING, data, len); SendCommandNG(CMD_PING, data, len);
if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) { if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) {
tms = msclock() - tms;
if (len) { if (len) {
bool error = (memcmp(data, resp.data.asBytes, len) != 0); bool error = (memcmp(data, resp.data.asBytes, len) != 0);
PrintAndLogEx((error) ? ERR : SUCCESS, "Ping response " _GREEN_("received") " and content () %s )", error ? _RED_("fail") : _GREEN_("ok")); PrintAndLogEx((error) ? ERR : SUCCESS, "Ping response " _GREEN_("received")
" in " _YELLOW_("%" PRIu64) " ms and content ( %s )",
tms, error ? _RED_("fail") : _GREEN_("ok"));
} else { } else {
PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received")); PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received")
" in " _YELLOW_("%" PRIu64) " ms", tms);
} }
} else } else
PrintAndLogEx(WARNING, "Ping response " _RED_("timeout")); PrintAndLogEx(WARNING, "Ping response " _RED_("timeout"));

View file

@ -1,4 +1,4 @@
//----------------------------------------------------------------------------- // //-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
// //
// This program is free software: you can redistribute it and/or modify // This program is free software: you can redistribute it and/or modify
@ -469,7 +469,7 @@ int CmdFlexdemod(const char *Cmd) {
sum += data[i++]; sum += data[i++];
} }
bits[bit] = (sum > 0) ? 1 : 0; bits[bit] = (sum > 0) ? 1 : 0;
PrintAndLogEx(NORMAL, "bit %d sum %d", bit, sum); // PrintAndLogEx(NORMAL, "bit %d sum %d", bit, sum);
} }
for (bit = 0; bit < 64; bit++) { for (bit = 0; bit < 64; bit++) {

View file

@ -528,8 +528,9 @@ static int CmdEM410xBrute(const char *Cmd) {
//The line start with # is comment, skip //The line start with # is comment, skip
if (buf[0] == '#') continue; if (buf[0] == '#') continue;
if (param_gethex(buf, 0, uid, 10)) { int uidlen = 0;
PrintAndLogEx(FAILED, "EM Tag IDs must include 5 hex bytes (10 hex symbols)"); if (param_gethex_ex(buf, 0, uid, &uidlen) && (uidlen != 10)) {
PrintAndLogEx(FAILED, "EM Tag IDs must include 5 hex bytes (10 hex symbols), got ( " _RED_("%d") " )", uidlen);
free(uidblock); free(uidblock);
fclose(f); fclose(f);
return PM3_ESOFT; return PM3_ESOFT;

View file

@ -514,6 +514,7 @@ int CmdEM4x05Dump(const char *Cmd) {
arg_param_begin, arg_param_begin,
arg_str0("p", "pwd", "<hex>", "password (00000000)"), arg_str0("p", "pwd", "<hex>", "password (00000000)"),
arg_str0("f", "file", "<fn>", "override filename prefix (optional). Default is based on UID"), arg_str0("f", "file", "<fn>", "override filename prefix (optional). Default is based on UID"),
arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -522,6 +523,7 @@ int CmdEM4x05Dump(const char *Cmd) {
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool nosave = arg_get_lit(ctx, 3);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t addr = 0; uint8_t addr = 0;
@ -693,6 +695,13 @@ int CmdEM4x05Dump(const char *Cmd) {
} else { } else {
} }
if (nosave) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Called with no save option");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
// all ok save dump to file // all ok save dump to file
if (success == PM3_SUCCESS) { if (success == PM3_SUCCESS) {
@ -709,9 +718,9 @@ int CmdEM4x05Dump(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
if (card_type == EM_4369 || card_type == EM_4469) if (card_type == EM_4369 || card_type == EM_4469)
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69, 4); pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x69);
else else
pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05, 4); pm3_save_dump(filename, (uint8_t *)data, sizeof(data), jsfEM4x05);
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return success; return success;
@ -741,16 +750,16 @@ int CmdEM4x05Read(const char *Cmd) {
bool use_pwd = false; bool use_pwd = false;
if (addr > 15) { if (addr > 15) {
PrintAndLogEx(ERR, "Address must be between 0 and 15"); PrintAndLogEx(ERR, "Address must be between 0 and 15, got " _RED_("%d"), addr);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (inputpwd == 0xFFFFFFFFFFFFFFFF) { if (inputpwd == 0xFFFFFFFFFFFFFFFF) {
PrintAndLogEx(INFO, "Reading address %02u", addr); PrintAndLogEx(INFO, "Reading address " _YELLOW_("%02u"), addr);
} else { } else {
pwd = (inputpwd & 0xFFFFFFFF); pwd = (inputpwd & 0xFFFFFFFF);
use_pwd = true; use_pwd = true;
PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd); PrintAndLogEx(INFO, "Reading address " _YELLOW_("%02u") " using password " _YELLOW_("%08X"), addr, pwd);
} }
uint32_t word = 0; uint32_t word = 0;
@ -818,14 +827,14 @@ int CmdEM4x05Write(const char *Cmd) {
if (use_pwd) { if (use_pwd) {
if (protect_operation) if (protect_operation)
PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd); PrintAndLogEx(INFO, "Writing protection words data " _YELLOW_("%08X") " using password " _YELLOW_("%08X"), data, pwd);
else else
PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd); PrintAndLogEx(INFO, "Writing address " _YELLOW_("%d") " data " _YELLOW_("%08X") " using password " _YELLOW_("%08X"), addr, data, pwd);
} else { } else {
if (protect_operation) if (protect_operation)
PrintAndLogEx(INFO, "Writing protection words data %08X", data); PrintAndLogEx(INFO, "Writing protection words data " _YELLOW_("%08X"), data);
else else
PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data); PrintAndLogEx(INFO, "Writing address " _YELLOW_("%d") " data " _YELLOW_("%08X"), addr, data);
} }
res = PM3_SUCCESS; res = PM3_SUCCESS;
@ -850,7 +859,7 @@ int CmdEM4x05Write(const char *Cmd) {
if (status == PM3_SUCCESS) if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Data written and verified"); PrintAndLogEx(SUCCESS, "Data written and verified");
else if (status == PM3_EFAILED) else if (status == PM3_EFAILED)
PrintAndLogEx(ERR, "Tag denied %s operation", protect_operation ? "Protect" : "Write"); PrintAndLogEx(ERR, "Tag denied " _RED_("%s") " operation", protect_operation ? "Protect" : "Write");
else else
PrintAndLogEx(DEBUG, "No answer from tag"); PrintAndLogEx(DEBUG, "No answer from tag");
@ -2020,7 +2029,7 @@ int CmdEM4x05Sniff(const char *Cmd) {
PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------"); PrintAndLogEx(SUCCESS, "-------+-------------+----------+-----+------------------------------------------------------------");
smartbuf bits = { 0 }; smartbuf bits = { 0 };
bits.ptr = malloc(EM4X05_BITS_BUFSIZE); bits.ptr = calloc(EM4X05_BITS_BUFSIZE, sizeof(uint8_t));
bits.size = EM4X05_BITS_BUFSIZE; bits.size = EM4X05_BITS_BUFSIZE;
bits.idx = 0; bits.idx = 0;
size_t idx = 0; size_t idx = 0;

View file

@ -194,7 +194,7 @@ int CmdEM4x50ELoad(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "dump filename (bin/eml/json)"), arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_param_end arg_param_end
}; };
@ -223,7 +223,7 @@ int CmdEM4x50ELoad(const char *Cmd) {
int CmdEM4x50ESave(const char *Cmd) { int CmdEM4x50ESave(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 esave", CLIParserInit(&ctx, "lf em 4x50 esave",
"Saves bin/eml/json dump file of emulator memory.", "Saves bin/json dump file of emulator memory.",
"lf em 4x50 esave -> use UID as filename\n" "lf em 4x50 esave -> use UID as filename\n"
"lf em 4x50 esave -f mydump\n" "lf em 4x50 esave -f mydump\n"
); );
@ -264,7 +264,7 @@ int CmdEM4x50ESave(const char *Cmd) {
FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4); FillFileNameByUID(fptr, (uint8_t *)&data[4 * EM4X50_DEVICE_ID], "-dump", 4);
} }
pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50, 4); pm3_save_dump(filename, data, DUMP_FILESIZE, jsfEM4x50);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -796,7 +796,7 @@ int CmdEM4x50Reader(const char *Cmd) {
int CmdEM4x50Dump(const char *Cmd) { int CmdEM4x50Dump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 dump", CLIParserInit(&ctx, "lf em 4x50 dump",
"Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format", "Reads all blocks/words from EM4x50 tag and saves dump in (bin/json) format",
"lf em 4x50 dump\n" "lf em 4x50 dump\n"
"lf em 4x50 dump -f mydump\n" "lf em 4x50 dump -f mydump\n"
"lf em 4x50 dump -p 12345678\n" "lf em 4x50 dump -p 12345678\n"
@ -805,7 +805,7 @@ int CmdEM4x50Dump(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "specify dump filename (bin/eml/json)"), arg_str0("f", "file", "<fn>", "specify dump filename"),
arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"), arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"),
arg_param_end arg_param_end
}; };
@ -867,7 +867,7 @@ int CmdEM4x50Dump(const char *Cmd) {
memcpy(data + (i * 4), words[i].byte, 4); memcpy(data + (i * 4), words[i].byte, 4);
} }
pm3_save_dump(filename, data, sizeof(data), jsfEM4x50, 4); pm3_save_dump(filename, data, sizeof(data), jsfEM4x50);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1113,7 +1113,7 @@ int CmdEM4x50Restore(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("u", "uid", "<hex>", "uid, 4 hex bytes, msb"), arg_str0("u", "uid", "<hex>", "uid, 4 hex bytes, msb"),
arg_str0("f", "file", "<fn>", "specify dump filename (bin/eml/json)"), arg_str0("f", "file", "<fn>", "specify a filename for dump file"),
arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"), arg_str0("p", "pwd", "<hex>", "password, 4 hex bytes, lsb"),
arg_param_end arg_param_end
}; };

View file

@ -44,6 +44,7 @@
#include "wiegand_formats.h" #include "wiegand_formats.h"
#include "wiegand_formatutils.h" #include "wiegand_formatutils.h"
#include "cmdlfem4x05.h" // EM defines #include "cmdlfem4x05.h" // EM defines
#include "loclass/cipherutils.h" // bitstreamout
#ifndef BITS #ifndef BITS
# define BITS 96 # define BITS 96
@ -399,14 +400,32 @@ static int CmdHIDClone(const char *Cmd) {
packed.Mid = mid; packed.Mid = mid;
packed.Bot = bot; packed.Bot = bot;
} else if (bin_len) { } else if (bin_len) {
int res = binstring_to_u96(&top, &mid, &bot, (const char *)bin);
if (res != bin_len) { uint8_t hex[12];
PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); memset(hex, 0, sizeof(hex));
return PM3_EINVARG; BitstreamOut_t bout = {hex, 0, 0 };
for (int i = 0; i < 96 - bin_len - 1; i++) {
pushBit(&bout, 0);
} }
packed.Top = top; // add binary sentinel bit.
packed.Mid = mid; pushBit(&bout, 1);
packed.Bot = bot;
// convert binary string to hex bytes
for (int i = 0; i < bin_len; i++) {
char c = bin[i];
if (c == '1')
pushBit(&bout, 1);
else if (c == '0')
pushBit(&bout, 0);
}
packed.Length = bin_len;
packed.Top = bytes_to_num(hex, 4);
packed.Mid = bytes_to_num(hex + 4, 4);
packed.Bot = bytes_to_num(hex + 8, 4);
add_HID_header(&packed);
} else { } else {
if (HIDPack(format_idx, &card, &packed, true) == false) { if (HIDPack(format_idx, &card, &packed, true) == false) {
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");

View file

@ -1127,7 +1127,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Dumping tag memory..."); PrintAndLogEx(SUCCESS, "Dumping tag memory...");
pm3_save_dump(filename, data, 48, jsfHitag, 4); pm3_save_dump(filename, data, 48, jsfHitag);
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -2217,7 +2217,7 @@ static int CmdT55xxDump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf t55xx dump", CLIParserInit(&ctx, "lf t55xx dump",
"This command dumps a T55xx card Page 0 block 0-7.\n" "This command dumps a T55xx card Page 0 block 0-7.\n"
"It will create three files (bin/eml/json)", "It will create two files (bin/json)",
"lf t55xx dump\n" "lf t55xx dump\n"
"lf t55xx dump -p aabbccdd --override\n" "lf t55xx dump -p aabbccdd --override\n"
"lf t55xx dump -f my_lf_dump" "lf t55xx dump -f my_lf_dump"
@ -2298,8 +2298,14 @@ static int CmdT55xxDump(const char *Cmd) {
} }
} }
if (nosave) {
PrintAndLogEx(INFO, "Called with no save option");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
// all ok, save dump to file // all ok, save dump to file
if (success && nosave == false) { if (success) {
// set default filename, if not set by user // set default filename, if not set by user
if (strlen(filename) == 0) { if (strlen(filename) == 0) {
@ -2315,17 +2321,13 @@ static int CmdT55xxDump(const char *Cmd) {
} }
// Swap endian so the files match the txt display // Swap endian so the files match the txt display
uint32_t data[T55x7_BLOCK_COUNT]; uint32_t data[T55x7_BLOCK_COUNT] = {0};
for (int i = 0; i < T55x7_BLOCK_COUNT; i++) { for (int i = 0; i < T55x7_BLOCK_COUNT; i++) {
data[i] = BSWAP_32(cardmem[i].blockdata); data[i] = BSWAP_32(cardmem[i].blockdata);
} }
// saveFileEML will add .eml extension to filename pm3_save_dump(filename, (uint8_t *)data, (T55x7_BLOCK_COUNT * sizeof(uint32_t)), jsfT55x7);
// saveFile (binary) passes in the .bin extension.
saveFileJSON(filename, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), NULL);
saveFileEML(filename, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t));
saveFile(filename, ".bin", data, sizeof(data));
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -2340,7 +2342,7 @@ static int CmdT55xxRestore(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename of dump file"), arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
arg_str0("p", "pwd", "<hex>", "password if target card has password set (4 hex bytes)"), arg_str0("p", "pwd", "<hex>", "password if target card has password set (4 hex bytes)"),
arg_param_end arg_param_end
}; };
@ -3498,7 +3500,8 @@ out:
// some return all page 1 (64 bits) and others return just that block (32 bits) // 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... // unfortunately the 64 bits makes this more likely to get a false positive...
bool tryDetectP1(bool getData) { bool tryDetectP1(bool getData) {
uint8_t preamble[] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1}; uint8_t preamble_atmel[] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1};
uint8_t preamble_silicon[] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1};
size_t startIdx = 0; size_t startIdx = 0;
uint8_t fc1 = 0, fc2 = 0, ans = 0; uint8_t fc1 = 0, fc2 = 0, ans = 0;
int clk = 0, firstClockEdge = 0; int clk = 0, firstClockEdge = 0;
@ -3512,63 +3515,115 @@ bool tryDetectP1(bool getData) {
// try fsk clock detect. if successful it cannot be any other type of modulation... (in theory...) // try fsk clock detect. if successful it cannot be any other type of modulation... (in theory...)
ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge); ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) { if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) {
if ((FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS) {
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if ((FSKrawDemod(0, 1, 0, 0, false) == PM3_SUCCESS) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
}
if (FSKrawDemod(0, 1, 0, 0, false) == PM3_SUCCESS) {
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
return false; return false;
} }
// try ask clock detect. it could be another type even if successful. // try ask clock detect. it could be another type even if successful.
clk = GetAskClock("", false); clk = GetAskClock("", false);
if (clk > 0) { if (clk > 0) {
if ((ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) && if (ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) {
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) &&
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
st = true; st = true;
if ((ASKDemod_ext(0, 1, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) && if (ASKDemod_ext(0, 1, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS) {
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if ((ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS) && if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
if (ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS) {
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if ((ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS) && if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
} }
if (ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS) {
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
}
// try NRZ clock detect. it could be another type even if successful. // try NRZ clock detect. it could be another type even if successful.
clk = GetNrzClock("", false); //has the most false positives :( clk = GetNrzClock("", false); //has the most false positives :(
if (clk > 0) { if (clk > 0) {
if ((NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS) && if (NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS) {
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if ((NRZrawDemod(0, 1, 1, false) == PM3_SUCCESS) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
} }
if (NRZrawDemod(0, 1, 1, false) == PM3_SUCCESS) {
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
}
// Fewer card uses PSK // Fewer card uses PSK
// try psk clock detect. if successful it cannot be any other type of modulation... (in theory...) // try psk clock detect. if successful it cannot be any other type of modulation... (in theory...)
clk = GetPskClock("", false); clk = GetPskClock("", false);
@ -3577,33 +3632,54 @@ bool tryDetectP1(bool getData) {
// save_restoreGB(GRAPH_SAVE); // save_restoreGB(GRAPH_SAVE);
// skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise) // skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise)
//CmdLtrim("-i 160"); //CmdLtrim("-i 160");
if ((PSKDemod(0, 0, 6, false) == PM3_SUCCESS) && if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) {
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
//save_restoreGB(GRAPH_RESTORE); //save_restoreGB(GRAPH_RESTORE);
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
if ((PSKDemod(0, 1, 6, false) == PM3_SUCCESS) &&
preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) && if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) { (g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
//save_restoreGB(GRAPH_RESTORE);
return true; return true;
} }
}
if (PSKDemod(0, 1, 6, false) == PM3_SUCCESS) {
//save_restoreGB(GRAPH_RESTORE);
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
}
// PSK2 - needs a call to psk1TOpsk2. // PSK2 - needs a call to psk1TOpsk2.
if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) { if (PSKDemod(0, 0, 6, false) == PM3_SUCCESS) {
psk1TOpsk2(g_DemodBuffer, g_DemodBufferLen); psk1TOpsk2(g_DemodBuffer, g_DemodBufferLen);
if (preambleSearchEx(g_DemodBuffer, preamble, sizeof(preamble), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
//save_restoreGB(GRAPH_RESTORE); //save_restoreGB(GRAPH_RESTORE);
if (preambleSearchEx(g_DemodBuffer, preamble_atmel, sizeof(preamble_atmel), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true;
}
if (preambleSearchEx(g_DemodBuffer, preamble_silicon, sizeof(preamble_silicon), &g_DemodBufferLen, &startIdx, false) &&
(g_DemodBufferLen == 32 || g_DemodBufferLen == 64)) {
return true; return true;
} }
} // inverse waves does not affect PSK2 demod } // inverse waves does not affect PSK2 demod
//undo trim samples //undo trim samples
//save_restoreGB(GRAPH_RESTORE); //save_restoreGB(GRAPH_RESTORE);
// no other modulation clocks = 2 or 4 so quit searching // no other modulation clocks = 2 or 4 so quit searching
if (fc1 != 8) return false; if (fc1 != 8) {
return false;
}
} }
return false; return false;
} }
// does this need to be a callable command? // does this need to be a callable command?

View file

@ -113,26 +113,48 @@ static int CmdNfcDecode(const char *Cmd) {
return res; return res;
} }
uint8_t *tmp = dump;
// if not MIFARE Classic default sizes, assume its Ultralight/NTAG
if (bytes_read != MIFARE_4K_MAX_BYTES
&& bytes_read != MIFARE_2K_MAX_BYTES
&& bytes_read != MIFARE_1K_MAX_BYTES
&& bytes_read != MIFARE_MINI_MAX_BYTES) {
uint8_t **pd = &tmp;
mfu_df_e df = detect_mfu_dump_format(pd, verbose);
if (df == MFU_DF_OLDBIN) {
tmp += OLD_MFU_DUMP_PREFIX_LENGTH + (4 * 4);
bytes_read -= OLD_MFU_DUMP_PREFIX_LENGTH + (4 * 4);
} else if (df == MFU_DF_NEWBIN) {
tmp += MFU_DUMP_PREFIX_LENGTH + (4 * 4);
bytes_read -= MFU_DUMP_PREFIX_LENGTH + (4 * 4);
}
pd = NULL;
} else {
// convert from MFC dump file to a pure NDEF byte array // convert from MFC dump file to a pure NDEF byte array
if (HasMADKey(dump)) { if (HasMADKey(tmp)) {
PrintAndLogEx(SUCCESS, "MFC dump file detected. Converting..."); PrintAndLogEx(SUCCESS, "MFC dump file detected. Converting...");
uint8_t ndef[4096] = {0}; uint8_t ndef[4096] = {0};
uint16_t ndeflen = 0; uint16_t ndeflen = 0;
if (convert_mad_to_arr(dump, bytes_read, ndef, &ndeflen) != PM3_SUCCESS) { if (convert_mad_to_arr(tmp, bytes_read, ndef, &ndeflen) != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Failed converting, aborting..."); PrintAndLogEx(FAILED, "Failed converting, aborting...");
free(dump); free(dump);
return PM3_ESOFT; return PM3_ESOFT;
} }
memcpy(dump, ndef, ndeflen); memcpy(tmp, ndef, ndeflen);
bytes_read = ndeflen; bytes_read = ndeflen;
} }
}
res = NDEFDecodeAndPrint(dump, bytes_read, verbose); res = NDEFDecodeAndPrint(tmp, bytes_read, verbose);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");
res = NDEFRecordsDecodeAndPrint(dump, bytes_read, verbose); res = NDEFRecordsDecodeAndPrint(tmp, bytes_read, verbose);
} }
free(dump); free(dump);

View file

@ -22,6 +22,7 @@
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
//#define PY_SSIZE_T_CLEAN //#define PY_SSIZE_T_CLEAN
#include <Python.h> #include <Python.h>
#include <ctype.h>
#include <wchar.h> #include <wchar.h>
#endif #endif

View file

@ -179,7 +179,7 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
if (T0 & 0x80) { if (T0 & 0x80) {
uint8_t TD1 = atr[2 + T1len]; uint8_t TD1 = atr[2 + T1len];
PrintAndLogEx(INFO, " - TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); PrintAndLogEx(INFO, " - TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol " _GREEN_("T%d"), TD1, TD1 & 0x0f);
protocol_T0_present = false; protocol_T0_present = false;
if ((TD1 & 0x0f) == 0) { if ((TD1 & 0x0f) == 0) {
protocol_T0_present = true; protocol_T0_present = true;
@ -204,7 +204,7 @@ static void PrintATR(uint8_t *atr, size_t atrlen) {
} }
if (TD1 & 0x80) { if (TD1 & 0x80) {
uint8_t TDi = atr[2 + T1len + TD1len]; uint8_t TDi = atr[2 + T1len + TD1len];
PrintAndLogEx(INFO, " - TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); PrintAndLogEx(INFO, " - TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol " _GREEN_("T%d"), TDi, TDi & 0x0f);
if ((TDi & 0x0f) == 0) { if ((TDi & 0x0f) == 0) {
protocol_T0_present = true; protocol_T0_present = true;
} }
@ -333,7 +333,7 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) {
needGetData = true; needGetData = true;
} }
if (needGetData == true) { if (needGetData) {
// Don't discard data we already received except the SW code. // Don't discard data we already received except the SW code.
// If we only received 1 byte, this is the echo of INS, we discard it. // If we only received 1 byte, this is the echo of INS, we discard it.
totallen -= 2; totallen -= 2;
@ -360,6 +360,7 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) {
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
payload->flags = SC_RAW | SC_LOG; payload->flags = SC_RAW | SC_LOG;
payload->len = sizeof(cmd_getresp); payload->len = sizeof(cmd_getresp);
payload->wait_delay = 0;
memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp)); memcpy(payload->data, cmd_getresp, sizeof(cmd_getresp));
clearCommandBuffer(); clearCommandBuffer();
@ -421,6 +422,7 @@ static int CmdSmartRaw(const char *Cmd) {
arg_lit0("s", NULL, "active smartcard with select (get ATR)"), arg_lit0("s", NULL, "active smartcard with select (get ATR)"),
arg_lit0("t", "tlv", "executes TLV decoder if it possible"), arg_lit0("t", "tlv", "executes TLV decoder if it possible"),
arg_lit0("0", NULL, "use protocol T=0"), arg_lit0("0", NULL, "use protocol T=0"),
arg_int0(NULL, "timeout", "<ms>", "Timeout in MS waiting for SIM to respond. (def 337ms)"),
arg_str1("d", "data", "<hex>", "bytes to send"), arg_str1("d", "data", "<hex>", "bytes to send"),
arg_param_end arg_param_end
}; };
@ -431,10 +433,11 @@ static int CmdSmartRaw(const char *Cmd) {
bool active_select = arg_get_lit(ctx, 3); bool active_select = arg_get_lit(ctx, 3);
bool decode_tlv = arg_get_lit(ctx, 4); bool decode_tlv = arg_get_lit(ctx, 4);
bool use_t0 = arg_get_lit(ctx, 5); bool use_t0 = arg_get_lit(ctx, 5);
int timeout = arg_get_int_def(ctx, 6, -1);
int dlen = 0; int dlen = 0;
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
int res = CLIParamHexToBuf(arg_get_str(ctx, 6), data, sizeof(data), &dlen); int res = CLIParamHexToBuf(arg_get_str(ctx, 7), data, sizeof(data), &dlen);
CLIParserFree(ctx); CLIParserFree(ctx);
if (res) { if (res) {
@ -458,6 +461,13 @@ static int CmdSmartRaw(const char *Cmd) {
payload->flags |= SC_SELECT; payload->flags |= SC_SELECT;
} }
payload->wait_delay = 0;
if (timeout > -1) {
payload->flags |= SC_WAIT;
payload->wait_delay = timeout;
}
PrintAndLogEx(DEBUG, "SIM Card timeout... %u ms", payload->wait_delay);
if (dlen > 0) { if (dlen > 0) {
if (use_t0) if (use_t0)
payload->flags |= SC_RAW_T0; payload->flags |= SC_RAW_T0;
@ -500,9 +510,9 @@ static int CmdSmartRaw(const char *Cmd) {
data[4] = 0; data[4] = 0;
} }
if (decode_tlv && len > 4) if (decode_tlv && len > 4) {
TLVPrintFromBuffer(buf, len - 2); TLVPrintFromBuffer(buf, len - 2);
else { } else {
if (len > 2) { if (len > 2) {
PrintAndLogEx(INFO, "Response data:"); PrintAndLogEx(INFO, "Response data:");
PrintAndLogEx(INFO, " # | bytes | ascii"); PrintAndLogEx(INFO, " # | bytes | ascii");
@ -518,16 +528,16 @@ out:
} }
static int CmdSmartUpgrade(const char *Cmd) { static int CmdSmartUpgrade(const char *Cmd) {
PrintAndLogEx(INFO, "-------------------------------------------------------------------"); PrintAndLogEx(INFO, "--------------------------------------------------------------------");
PrintAndLogEx(WARNING, _RED_("WARNING") " - sim module firmware upgrade"); PrintAndLogEx(WARNING, _RED_("WARNING") " - sim module firmware upgrade");
PrintAndLogEx(WARNING, _RED_("A dangerous command, do wrong and you could brick the sim module")); PrintAndLogEx(WARNING, _RED_("A dangerous command, do wrong and you could brick the sim module"));
PrintAndLogEx(INFO, "-------------------------------------------------------------------"); PrintAndLogEx(INFO, "--------------------------------------------------------------------");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "smart upgrade", CLIParserInit(&ctx, "smart upgrade",
"Upgrade RDV4 sim module firmware", "Upgrade RDV4 sim module firmware",
"smart upgrade -f sim013.bin" "smart upgrade -f sim014.bin"
); );
void *argtable[] = { void *argtable[] = {
@ -585,9 +595,10 @@ static int CmdSmartUpgrade(const char *Cmd) {
} }
hashstring[128] = '\0'; hashstring[128] = '\0';
int hash1n = 0;
uint8_t hash_1[64]; uint8_t hash_1[64];
if (param_gethex(hashstring, 0, hash_1, 128)) { if (param_gethex_ex(hashstring, 0, hash_1, &hash1n) && hash1n != 128) {
PrintAndLogEx(FAILED, "Couldn't read SHA-512 file"); PrintAndLogEx(FAILED, "Couldn't read SHA-512 file. expect 128 hex bytes, got ( "_RED_("%d") " )", hash1n);
free(hashstring); free(hashstring);
free(firmware); free(firmware);
return PM3_ESOFT; return PM3_ESOFT;
@ -903,6 +914,7 @@ static void smart_brute_prim(void) {
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + 5); smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + 5);
payload->flags = SC_RAW_T0; payload->flags = SC_RAW_T0;
payload->len = 5; payload->len = 5;
payload->wait_delay = 0;
memcpy(payload->data, get_card_data + i, 5); memcpy(payload->data, get_card_data + i, 5);
clearCommandBuffer(); clearCommandBuffer();
@ -946,6 +958,7 @@ static int smart_brute_sfi(bool decodeTLV) {
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(READ_RECORD)); smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(READ_RECORD));
payload->flags = SC_RAW_T0; payload->flags = SC_RAW_T0;
payload->len = sizeof(READ_RECORD); payload->len = sizeof(READ_RECORD);
payload->wait_delay = 0;
memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD)); memcpy(payload->data, READ_RECORD, sizeof(READ_RECORD));
clearCommandBuffer(); clearCommandBuffer();
@ -1099,7 +1112,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + hexlen); smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + hexlen);
payload->flags = SC_RAW_T0; payload->flags = SC_RAW_T0;
payload->len = hexlen; payload->len = hexlen;
payload->wait_delay = 0;
memcpy(payload->data, cmddata, hexlen); memcpy(payload->data, cmddata, hexlen);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + hexlen); SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + hexlen);
@ -1335,6 +1348,7 @@ int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCa
payload->flags |= (SC_SELECT | SC_CONNECT); payload->flags |= (SC_SELECT | SC_CONNECT);
} }
payload->len = datainlen; payload->len = datainlen;
payload->wait_delay = 0;
memcpy(payload->data, datain, datainlen); memcpy(payload->data, datain, datainlen);
clearCommandBuffer(); clearCommandBuffer();
@ -1366,8 +1380,9 @@ int ExchangeAPDUSC(bool verbose, uint8_t *datain, int datainlen, bool activateCa
} }
bool smart_select(bool verbose, smart_card_atr_t *atr) { bool smart_select(bool verbose, smart_card_atr_t *atr) {
if (atr) if (atr) {
memset(atr, 0, sizeof(smart_card_atr_t)); memset(atr, 0, sizeof(smart_card_atr_t));
}
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_SMART_ATR, NULL, 0); SendCommandNG(CMD_SMART_ATR, NULL, 0);
@ -1385,8 +1400,9 @@ bool smart_select(bool verbose, smart_card_atr_t *atr) {
smart_card_atr_t card; smart_card_atr_t card;
memcpy(&card, (smart_card_atr_t *)resp.data.asBytes, sizeof(smart_card_atr_t)); memcpy(&card, (smart_card_atr_t *)resp.data.asBytes, sizeof(smart_card_atr_t));
if (atr) if (atr) {
memcpy(atr, &card, sizeof(smart_card_atr_t)); memcpy(atr, &card, sizeof(smart_card_atr_t));
}
if (verbose) if (verbose)
PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len));

View file

@ -666,19 +666,28 @@ int TestProxmark(pm3_device_t *dev) {
g_conn.send_via_fpc_usart = g_pm3_capabilities.via_fpc; g_conn.send_via_fpc_usart = g_pm3_capabilities.via_fpc;
g_conn.uart_speed = g_pm3_capabilities.baudrate; g_conn.uart_speed = g_pm3_capabilities.baudrate;
bool is_tcp_conn = (memcmp(g_conn.serial_port_name, "tcp:", 4) == 0); bool is_tcp_conn = (g_conn.send_via_ip == PM3_TCPv4 || g_conn.send_via_ip == PM3_TCPv6);
bool is_bt_conn = (memcmp(g_conn.serial_port_name, "bt:", 3) == 0); bool is_bt_conn = (memcmp(g_conn.serial_port_name, "bt:", 3) == 0);
bool is_udp_conn = (g_conn.send_via_ip == PM3_UDPv4 || g_conn.send_via_ip == PM3_UDPv6);
PrintAndLogEx(INFO, "Communicating with PM3 over %s%s%s", PrintAndLogEx(INFO, "Communicating with PM3 over %s%s%s%s",
(g_conn.send_via_fpc_usart) ? _YELLOW_("FPC UART") : _YELLOW_("USB-CDC"), (g_conn.send_via_fpc_usart) ? _YELLOW_("FPC UART") : _YELLOW_("USB-CDC"),
(is_tcp_conn) ? " over " _YELLOW_("TCP") : "", (is_tcp_conn) ? " over " _YELLOW_("TCP") : "",
(is_bt_conn) ? " over " _YELLOW_("BT") : "" (is_bt_conn) ? " over " _YELLOW_("BT") : "",
(is_udp_conn) ? " over " _YELLOW_("UDP") : ""
); );
if (g_conn.send_via_fpc_usart) { if (g_conn.send_via_fpc_usart) {
PrintAndLogEx(INFO, "PM3 UART serial baudrate: " _YELLOW_("%u") "\n", g_conn.uart_speed); PrintAndLogEx(INFO, "PM3 UART serial baudrate: " _YELLOW_("%u") "\n", g_conn.uart_speed);
} else { } else {
int res = uart_reconfigure_timeouts(is_tcp_conn ? UART_TCP_CLIENT_RX_TIMEOUT_MS : UART_USB_CLIENT_RX_TIMEOUT_MS); int res;
if (g_conn.send_via_local_ip) {
// (g_conn.send_via_local_ip == true) -> ((is_tcp_conn || is_udp_conn) == true)
res = uart_reconfigure_timeouts(is_tcp_conn ? UART_TCP_LOCAL_CLIENT_RX_TIMEOUT_MS : UART_UDP_LOCAL_CLIENT_RX_TIMEOUT_MS);
} else if (is_tcp_conn || is_udp_conn) {
res = uart_reconfigure_timeouts(UART_NET_CLIENT_RX_TIMEOUT_MS);
} else {
res = uart_reconfigure_timeouts(UART_USB_CLIENT_RX_TIMEOUT_MS);
}
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
return res; return res;
} }
@ -789,7 +798,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms
show_warning = false; show_warning = false;
} }
// just to avoid CPU busy loop: // just to avoid CPU busy loop:
msleep(10); msleep(1);
} }
return false; return false;
} }

View file

@ -54,6 +54,14 @@ typedef enum {
FPGA_MEM, FPGA_MEM,
} DeviceMemType_t; } DeviceMemType_t;
typedef enum {
PM3_TCPv4,
PM3_TCPv6,
PM3_UDPv4,
PM3_UDPv6,
PM3_NONE,
} CommunicationProtocol_t;
typedef struct { typedef struct {
bool run; // If TRUE, continue running the uart_communication thread bool run; // If TRUE, continue running the uart_communication thread
bool block_after_ACK; // if true, block after receiving an ACK package bool block_after_ACK; // if true, block after receiving an ACK package
@ -62,6 +70,10 @@ typedef struct {
bool send_with_crc_on_fpc; bool send_with_crc_on_fpc;
// "Session" flag, to tell via which interface next msgs are sent: USB or FPC USART // "Session" flag, to tell via which interface next msgs are sent: USB or FPC USART
bool send_via_fpc_usart; bool send_via_fpc_usart;
// to tell if we are using TCP/UDP/TCP(IPv6)/UDP(IPv6)
CommunicationProtocol_t send_via_ip;
// to tell if the target address is local address(127.0.0.1/localhost/::1)
bool send_via_local_ip;
// To memorise baudrate // To memorise baudrate
uint32_t uart_speed; uint32_t uart_speed;
uint16_t last_command; uint16_t last_command;

View file

@ -15,7 +15,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// asn.1 dumping // asn.1 dumping
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define _POSIX_C_SOURCE 200809L // need for strnlen()
#include "asn1dump.h" #include "asn1dump.h"
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
@ -344,17 +344,17 @@ static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag
} else { } else {
const char *ppstr = NULL; const char *ppstr = NULL;
mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr); mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr);
if (ppstr && strnlen(ppstr, 1)) { if (ppstr && str_nlen(ppstr, 1)) {
PrintAndLogEx(NORMAL, " (%s)", ppstr); PrintAndLogEx(NORMAL, " (%s)", ppstr);
return; return;
} }
mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr); mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr);
if (ppstr && strnlen(ppstr, 1)) { if (ppstr && str_nlen(ppstr, 1)) {
PrintAndLogEx(NORMAL, " (%s)", ppstr); PrintAndLogEx(NORMAL, " (%s)", ppstr);
return; return;
} }
mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr); mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr);
if (ppstr && strnlen(ppstr, 1)) { if (ppstr && str_nlen(ppstr, 1)) {
PrintAndLogEx(NORMAL, " (%s)", ppstr); PrintAndLogEx(NORMAL, " (%s)", ppstr);
return; return;
} }

View file

@ -629,8 +629,10 @@ int blowfish_decrypt(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output,
mbedtls_blowfish_init(&blow); mbedtls_blowfish_init(&blow);
if (mbedtls_blowfish_setkey(&blow, key, 64)) if (mbedtls_blowfish_setkey(&blow, key, 64))
return 1; return 1;
if (mbedtls_blowfish_crypt_cbc(&blow, MBEDTLS_BLOWFISH_DECRYPT, length, iiv, input, output)) if (mbedtls_blowfish_crypt_cbc(&blow, MBEDTLS_BLOWFISH_DECRYPT, length, iiv, input, output))
return 2; return 2;
mbedtls_blowfish_free(&blow); mbedtls_blowfish_free(&blow);
return 0; return 0;
@ -647,7 +649,7 @@ int ansi_x963_sha256(uint8_t *sharedSecret, size_t sharedSecretLen, uint8_t *sha
uint32_t counter = 0x00000001; uint32_t counter = 0x00000001;
for (int i = 0; i < (keyDataLen / 32); ++i) { for (int i = 0; i < (keyDataLen / 32); ++i) {
uint8_t *hashMaterial = malloc(4 + sharedSecretLen + sharedInfoLen); uint8_t *hashMaterial = calloc(4 + sharedSecretLen + sharedInfoLen, sizeof(uint8_t));
memcpy(hashMaterial, sharedSecret, sharedSecretLen); memcpy(hashMaterial, sharedSecret, sharedSecretLen);
hashMaterial[sharedSecretLen] = (counter >> 24); hashMaterial[sharedSecretLen] = (counter >> 24);
hashMaterial[sharedSecretLen + 1] = (counter >> 16) & 0xFF; hashMaterial[sharedSecretLen + 1] = (counter >> 16) & 0xFF;

View file

@ -50,12 +50,14 @@ static void ParamLoadDefaults(struct tlvdb *tlvRoot) {
TLV_ADD(0x9F1A, "ru"); TLV_ADD(0x9F1A, "ru");
// 5F2A:(Transaction Currency Code) len:2 // 5F2A:(Transaction Currency Code) len:2
// USD 840, EUR 978, RUR 810, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999 // USD 840, EUR 978, RUR 810, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999
TLV_ADD(0x5F2A, "\x09\x80"); TLV_ADD(0x5F2A, "\x090\x78");
// 9A:(Transaction Date) len:3 // 9A:(Transaction Date) len:3
TLV_ADD(0x9A, "\x00\x00\x00"); TLV_ADD(0x9A, "\x00\x00\x00");
//9C:(Transaction Type) len:1 | 00 => Goods and service #01 => Cash // 9C:(Transaction Type) len:1
// | 00 => Goods and Service
// | 01 => Cash
TLV_ADD(0x9C, "\x00"); TLV_ADD(0x9C, "\x00");
// 9F37 Unpredictable Number len:4 // 9F37 Unpredictable Number (UN) len:4
TLV_ADD(0x9F37, "\x01\x02\x03\x04"); TLV_ADD(0x9F37, "\x01\x02\x03\x04");
// 9F6A Unpredictable Number (MSD for UDOL) len:4 // 9F6A Unpredictable Number (MSD for UDOL) len:4
TLV_ADD(0x9F6A, "\x01\x02\x03\x04"); TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
@ -65,7 +67,7 @@ static void ParamLoadDefaults(struct tlvdb *tlvRoot) {
// all OK TVR // all OK TVR
TLV_ADD(0x95, "\x00\x00\x00\x00\x00"); TLV_ADD(0x95, "\x00\x00\x00\x00\x00");
// 9F4E Merchant Name and Location len:x // 9F4E Merchant Name and Location len:x
TLV_ADD(0x9F4E, "proxmrk3rdv\x00"); TLV_ADD(0x9F4E, "proxmark3rdv4\x00");
} }
static void PrintChannel(Iso7816CommandChannel channel) { static void PrintChannel(Iso7816CommandChannel channel) {
@ -298,14 +300,14 @@ static int emv_parse_track1(const uint8_t *d, size_t n, bool verbose) {
case 0: { case 0: {
size_t a = strlen(token); size_t a = strlen(token);
if (a == 16) { if (a == 16) {
PrintAndLogEx(INFO, "PAN...................... %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c", PrintAndLogEx(INFO, "PAN...................... " _GREEN_("%c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c"),
token[1], token[2], token[3], token[4], token[1], token[2], token[3], token[4],
token[5], token[6], token[7], token[8], token[5], token[6], token[7], token[8],
token[9], token[10], token[11], token[12], token[9], token[10], token[11], token[12],
token[13], token[14], token[15], token[16] token[13], token[14], token[15], token[16]
); );
} else if (a == 19) { } else if (a == 19) {
PrintAndLogEx(INFO, "PAN...................... %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c", PrintAndLogEx(INFO, "PAN...................... " _GREEN_("%c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c"),
token[1], token[2], token[3], token[4], token[1], token[2], token[3], token[4],
token[5], token[6], token[7], token[8], token[5], token[6], token[7], token[8],
token[9], token[10], token[11], token[12], token[9], token[10], token[11], token[12],
@ -362,7 +364,7 @@ static int emv_parse_track2(const uint8_t *d, size_t n, bool verbose) {
if (tmp[0] == ';') if (tmp[0] == ';')
tmp++; tmp++;
PrintAndLogEx(INFO, "PAN...................... %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c", PrintAndLogEx(INFO, "PAN...................... "_GREEN_("%c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c"),
tmp[0], tmp[1], tmp[2], tmp[3], tmp[0], tmp[1], tmp[2], tmp[3],
tmp[4], tmp[5], tmp[6], tmp[7], tmp[4], tmp[5], tmp[6], tmp[7],
tmp[8], tmp[9], tmp[10], tmp[11], tmp[8], tmp[9], tmp[10], tmp[11],
@ -479,7 +481,7 @@ static int emv_parse_card_details(uint8_t *response, size_t reslen, bool verbose
if (apan_full != NULL) { if (apan_full != NULL) {
const struct tlv *apan_tlv = tlvdb_get_tlv(apan_full); const struct tlv *apan_tlv = tlvdb_get_tlv(apan_full);
if (apan_tlv->len == 8) { if (apan_tlv->len == 8) {
PrintAndLogEx(INFO, "PAN.................. " _YELLOW_("%02x%02x %02x%02x %02x%02x %02x%02x"), PrintAndLogEx(INFO, "PAN.................. " _GREEN_("%02x%02x %02x%02x %02x%02x %02x%02x"),
apan_tlv->value[0], apan_tlv->value[0],
apan_tlv->value[1], apan_tlv->value[1],
apan_tlv->value[2], apan_tlv->value[2],
@ -543,6 +545,33 @@ static int emv_parse_card_details(uint8_t *response, size_t reslen, bool verbose
// Track 3 Data // Track 3 Data
// to be impl. // to be impl.
// Unpredicable Number (UN)
struct tlvdb *un1_full = tlvdb_find_full(root, 0x9f37);
if (un1_full != NULL) {
const struct tlv *un1_tlv = tlvdb_get_tlv(un1_full);
if (un1_tlv->len) {
PrintAndLogEx(INFO, "9F37 Unpredicable Number... " _YELLOW_("%s"), sprint_hex_inrow(un1_tlv->value, un1_tlv->len));
}
}
// Unpredicable Number (UN)
struct tlvdb *un_full = tlvdb_find_full(root, 0x9f6a);
if (un_full != NULL) {
const struct tlv *un_tlv = tlvdb_get_tlv(un_full);
if (un_tlv->len) {
PrintAndLogEx(INFO, "9F6A Unpredicable Number... " _YELLOW_("%s"), sprint_hex_inrow(un_tlv->value, un_tlv->len));
emv_parse_track2(un_tlv->value, un_tlv->len, verbose);
}
}
struct tlvdb *merch_full = tlvdb_find_full(root, 0x9f4e);
if (merch_full != NULL) {
const struct tlv *merch_tlv = tlvdb_get_tlv(merch_full);
if (merch_tlv->len) {
PrintAndLogEx(INFO, "Merchant Name and Location... " _YELLOW_("%s"), sprint_hex_inrow(merch_tlv->value, merch_tlv->len));
}
}
tlvdb_free(root); tlvdb_free(root);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -571,7 +600,7 @@ static int CmdEMVSelect(const char *Cmd) {
bool activateField = arg_get_lit(ctx, 1); bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2); bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3); bool show_apdu = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4); bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 5)) if (arg_get_lit(ctx, 5))
@ -580,7 +609,7 @@ static int CmdEMVSelect(const char *Cmd) {
CLIGetHexWithReturn(ctx, 6, data, &datalen); CLIGetHexWithReturn(ctx, 6, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// exec // exec
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
@ -597,6 +626,7 @@ static int CmdEMVSelect(const char *Cmd) {
if (decodeTLV) if (decodeTLV)
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);
SetAPDULogging(false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -621,7 +651,7 @@ static int CmdEMVSearch(const char *Cmd) {
bool activateField = arg_get_lit(ctx, 1); bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2); bool leaveSignalON = arg_get_lit(ctx, 2);
bool APDULogging = arg_get_lit(ctx, 3); bool show_apdu = arg_get_lit(ctx, 3);
bool decodeTLV = arg_get_lit(ctx, 4); bool decodeTLV = arg_get_lit(ctx, 4);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
@ -632,13 +662,14 @@ static int CmdEMVSearch(const char *Cmd) {
PrintChannel(channel); PrintChannel(channel);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
const char *al = "Applets list"; const char *al = "Applets list";
struct tlvdb *t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); struct tlvdb *t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
if (EMVSearch(channel, activateField, leaveSignalON, decodeTLV, t, false)) { if (EMVSearch(channel, activateField, leaveSignalON, decodeTLV, t, false)) {
tlvdb_free(t); tlvdb_free(t);
SetAPDULogging(false);
return PM3_ERFTRANS; return PM3_ERFTRANS;
} }
@ -651,6 +682,7 @@ static int CmdEMVSearch(const char *Cmd) {
tlvdb_free(t); tlvdb_free(t);
SetAPDULogging(false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -678,19 +710,23 @@ static int CmdEMVPPSE(const char *Cmd) {
bool activateField = arg_get_lit(ctx, 1); bool activateField = arg_get_lit(ctx, 1);
bool leaveSignalON = arg_get_lit(ctx, 2); bool leaveSignalON = arg_get_lit(ctx, 2);
uint8_t PSENum = 2; uint8_t PSENum = 2;
if (arg_get_lit(ctx, 3)) if (arg_get_lit(ctx, 3)) {
PSENum = 1; PSENum = 1;
if (arg_get_lit(ctx, 4)) }
if (arg_get_lit(ctx, 4)) {
PSENum = 2; PSENum = 2;
bool APDULogging = arg_get_lit(ctx, 5); }
bool show_apdu = arg_get_lit(ctx, 5);
bool decodeTLV = arg_get_lit(ctx, 6); bool decodeTLV = arg_get_lit(ctx, 6);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 7)) if (arg_get_lit(ctx, 7)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// exec // exec
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
@ -707,6 +743,7 @@ static int CmdEMVPPSE(const char *Cmd) {
if (decodeTLV) if (decodeTLV)
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);
SetAPDULogging(false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -738,16 +775,17 @@ static int CmdEMVGPO(const char *Cmd) {
bool leaveSignalON = arg_get_lit(ctx, 1); bool leaveSignalON = arg_get_lit(ctx, 1);
bool paramsLoadFromFile = arg_get_lit(ctx, 2); bool paramsLoadFromFile = arg_get_lit(ctx, 2);
bool dataMakeFromPDOL = arg_get_lit(ctx, 3); bool dataMakeFromPDOL = arg_get_lit(ctx, 3);
bool APDULogging = arg_get_lit(ctx, 4); bool show_apdu = arg_get_lit(ctx, 4);
bool decodeTLV = arg_get_lit(ctx, 5); bool decodeTLV = arg_get_lit(ctx, 5);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 6)) if (arg_get_lit(ctx, 6)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIGetHexWithReturn(ctx, 7, data, &datalen); CLIGetHexWithReturn(ctx, 7, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// Init TLV tree // Init TLV tree
const char *alr = "Root terminal TLV tree"; const char *alr = "Root terminal TLV tree";
@ -775,6 +813,7 @@ static int CmdEMVGPO(const char *Cmd) {
PrintAndLogEx(ERR, "Can't create PDOL TLV."); PrintAndLogEx(ERR, "Can't create PDOL TLV.");
tlvdb_free(tmp_ext); tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
SetAPDULogging(false);
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
@ -790,8 +829,10 @@ static int CmdEMVGPO(const char *Cmd) {
PrintAndLogEx(ERR, "Can't create PDOL data."); PrintAndLogEx(ERR, "Can't create PDOL data.");
tlvdb_free(tmp_ext); tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
if (pdol_data_tlv != &data_tlv) if (pdol_data_tlv != &data_tlv) {
free(pdol_data_tlv); free(pdol_data_tlv);
}
SetAPDULogging(false);
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(INFO, "PDOL data[%zu]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); PrintAndLogEx(INFO, "PDOL data[%zu]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
@ -817,6 +858,7 @@ static int CmdEMVGPO(const char *Cmd) {
if (decodeTLV) if (decodeTLV)
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);
SetAPDULogging(false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -843,11 +885,12 @@ static int CmdEMVReadRecord(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool leaveSignalON = arg_get_lit(ctx, 1); bool leaveSignalON = arg_get_lit(ctx, 1);
bool APDULogging = arg_get_lit(ctx, 2); bool show_apdu = arg_get_lit(ctx, 2);
bool decodeTLV = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 3);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 4)) if (arg_get_lit(ctx, 4)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIGetHexWithReturn(ctx, 5, data, &datalen); CLIGetHexWithReturn(ctx, 5, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -857,13 +900,14 @@ static int CmdEMVReadRecord(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// exec // exec
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL);
SetAPDULogging(false);
if (sw) if (sw)
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
@ -910,14 +954,17 @@ static int CmdEMVAC(const char *Cmd) {
bool trTypeCDA = arg_get_lit(ctx, 2); bool trTypeCDA = arg_get_lit(ctx, 2);
uint8_t termDecision = 0xff; uint8_t termDecision = 0xff;
if (arg_get_str_len(ctx, 3)) { if (arg_get_str_len(ctx, 3)) {
if (!strncmp(arg_get_str(ctx, 3)->sval[0], "aac", 4)) if (!strncmp(arg_get_str(ctx, 3)->sval[0], "aac", 4)) {
termDecision = EMVAC_AAC; termDecision = EMVAC_AAC;
if (!strncmp(arg_get_str(ctx, 3)->sval[0], "tc", 4)) }
if (!strncmp(arg_get_str(ctx, 3)->sval[0], "tc", 4)) {
termDecision = EMVAC_TC; termDecision = EMVAC_TC;
if (!strncmp(arg_get_str(ctx, 3)->sval[0], "arqc", 4)) }
if (!strncmp(arg_get_str(ctx, 3)->sval[0], "arqc", 4)) {
termDecision = EMVAC_ARQC; termDecision = EMVAC_ARQC;
}
if (termDecision == 0xff) { if (termDecision == 0xFF) {
PrintAndLogEx(ERR, "ERROR: can't find terminal decision '%s'", arg_get_str(ctx, 3)->sval[0]); PrintAndLogEx(ERR, "ERROR: can't find terminal decision '%s'", arg_get_str(ctx, 3)->sval[0]);
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
@ -925,22 +972,25 @@ static int CmdEMVAC(const char *Cmd) {
} else { } else {
termDecision = EMVAC_TC; termDecision = EMVAC_TC;
} }
if (trTypeCDA)
if (trTypeCDA) {
termDecision = termDecision | EMVAC_CDAREQ; termDecision = termDecision | EMVAC_CDAREQ;
}
bool paramsLoadFromFile = arg_get_lit(ctx, 4); bool paramsLoadFromFile = arg_get_lit(ctx, 4);
bool dataMakeFromCDOL = arg_get_lit(ctx, 5); bool dataMakeFromCDOL = arg_get_lit(ctx, 5);
bool APDULogging = arg_get_lit(ctx, 6); bool show_apdu = arg_get_lit(ctx, 6);
bool decodeTLV = arg_get_lit(ctx, 7); bool decodeTLV = arg_get_lit(ctx, 7);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 8)) if (arg_get_lit(ctx, 8)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIGetHexWithReturn(ctx, 9, data, &datalen); CLIGetHexWithReturn(ctx, 9, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// Init TLV tree // Init TLV tree
const char *alr = "Root terminal TLV tree"; const char *alr = "Root terminal TLV tree";
@ -969,6 +1019,7 @@ static int CmdEMVAC(const char *Cmd) {
PrintAndLogEx(ERR, "Can't create CDOL TLV."); PrintAndLogEx(ERR, "Can't create CDOL TLV.");
tlvdb_free(tmp_ext); tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
SetAPDULogging(false);
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
@ -985,6 +1036,7 @@ static int CmdEMVAC(const char *Cmd) {
size_t len = 0; size_t len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
SetAPDULogging(false);
if (cdol_data_tlv != &data_tlv) if (cdol_data_tlv != &data_tlv)
free(cdol_data_tlv); free(cdol_data_tlv);
@ -1023,20 +1075,22 @@ static int CmdEMVGenerateChallenge(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool leaveSignalON = arg_get_lit(ctx, 1); bool leaveSignalON = arg_get_lit(ctx, 1);
bool APDULogging = arg_get_lit(ctx, 2); bool show_apdu = arg_get_lit(ctx, 2);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 3)) if (arg_get_lit(ctx, 3)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// exec // exec
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL);
SetAPDULogging(false);
if (sw) if (sw)
PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
@ -1046,8 +1100,9 @@ static int CmdEMVGenerateChallenge(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Challenge: %s", sprint_hex(buf, len)); PrintAndLogEx(SUCCESS, "Challenge: %s", sprint_hex(buf, len));
if (len != 4 && len != 8) if (len != 4 && len != 8) {
PrintAndLogEx(WARNING, "Length of challenge must be 4 or 8, but it %zu", len); PrintAndLogEx(WARNING, "Length of challenge must be 4 or 8, got " _YELLOW_("%zu"), len);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1081,16 +1136,17 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
bool leaveSignalON = arg_get_lit(ctx, 1); bool leaveSignalON = arg_get_lit(ctx, 1);
bool paramsLoadFromFile = arg_get_lit(ctx, 2); bool paramsLoadFromFile = arg_get_lit(ctx, 2);
bool dataMakeFromDDOL = arg_get_lit(ctx, 3); bool dataMakeFromDDOL = arg_get_lit(ctx, 3);
bool APDULogging = arg_get_lit(ctx, 4); bool show_apdu = arg_get_lit(ctx, 4);
bool decodeTLV = arg_get_lit(ctx, 5); bool decodeTLV = arg_get_lit(ctx, 5);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 6)) if (arg_get_lit(ctx, 6)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
CLIGetHexWithReturn(ctx, 7, data, &datalen); CLIGetHexWithReturn(ctx, 7, data, &datalen);
CLIParserFree(ctx); CLIParserFree(ctx);
SetAPDULogging(APDULogging); SetAPDULogging(show_apdu);
// Init TLV tree // Init TLV tree
const char *alr = "Root terminal TLV tree"; const char *alr = "Root terminal TLV tree";
@ -1119,6 +1175,7 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
PrintAndLogEx(ERR, "Can't create DDOL TLV."); PrintAndLogEx(ERR, "Can't create DDOL TLV.");
tlvdb_free(tmp_ext); tlvdb_free(tmp_ext);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
SetAPDULogging(false);
return PM3_ESOFT; return PM3_ESOFT;
} }
} else { } else {
@ -1135,6 +1192,7 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
size_t len = 0; size_t len = 0;
uint16_t sw = 0; uint16_t sw = 0;
int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL);
SetAPDULogging(false);
if (ddol_data_tlv != &data_tlv) if (ddol_data_tlv != &data_tlv)
free(ddol_data_tlv); free(ddol_data_tlv);
@ -1154,7 +1212,14 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;} #define dreturn(n) { \
free(pdol_data_tlv); \
tlvdb_free(tlvSelect); \
tlvdb_free(tlvRoot); \
DropFieldEx( channel ); \
SetAPDULogging(false); \
return n; \
}
static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) { static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) {
@ -1297,21 +1362,24 @@ static int CmdEMVExec(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool activateField = arg_get_lit(ctx, 1); bool activateField = arg_get_lit(ctx, 1);
bool showAPDU = arg_get_lit(ctx, 2); bool show_apdu = arg_get_lit(ctx, 2);
bool decodeTLV = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 3);
bool paramLoadJSON = arg_get_lit(ctx, 4); bool paramLoadJSON = arg_get_lit(ctx, 4);
bool forceSearch = arg_get_lit(ctx, 5); bool forceSearch = arg_get_lit(ctx, 5);
enum TransactionType TrType = TT_MSD; enum TransactionType TrType = TT_MSD;
if (arg_get_lit(ctx, 7)) if (arg_get_lit(ctx, 7)) {
TrType = TT_QVSDCMCHIP; TrType = TT_QVSDCMCHIP;
}
if (arg_get_lit(ctx, 8)) if (arg_get_lit(ctx, 8)) {
TrType = TT_CDA; TrType = TT_CDA;
}
if (arg_get_lit(ctx, 9)) if (arg_get_lit(ctx, 9)) {
TrType = TT_VSDC; TrType = TT_VSDC;
}
bool GenACGPO = arg_get_lit(ctx, 10); bool GenACGPO = arg_get_lit(ctx, 10);
@ -1324,14 +1392,14 @@ static int CmdEMVExec(const char *Cmd) {
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2; uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
CLIParserFree(ctx); CLIParserFree(ctx);
if (!IfPm3Smartcard()) { if (IfPm3Smartcard() == false) {
if (channel == CC_CONTACT) { if (channel == CC_CONTACT) {
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support. Exiting."); PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support. Exiting.");
return PM3_EDEVNOTSUPP; return PM3_EDEVNOTSUPP;
} }
} }
SetAPDULogging(showAPDU); SetAPDULogging(show_apdu);
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
@ -1357,7 +1425,7 @@ static int CmdEMVExec(const char *Cmd) {
// PPSE // PPSE
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "* PPSE."); PrintAndLogEx(INFO, "* PPSE.");
SetAPDULogging(showAPDU); SetAPDULogging(show_apdu);
res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect);
// check PPSE instead of PSE and vice versa // check PPSE instead of PSE and vice versa
@ -1398,7 +1466,7 @@ static int CmdEMVExec(const char *Cmd) {
// Select // Select
PrintAndLogEx(INFO, "\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen)); PrintAndLogEx(INFO, "\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen));
SetAPDULogging(showAPDU); SetAPDULogging(show_apdu);
res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot);
if (res) { if (res) {
@ -1406,8 +1474,9 @@ static int CmdEMVExec(const char *Cmd) {
dreturn(PM3_ERFTRANS); dreturn(PM3_ERFTRANS);
} }
if (decodeTLV) if (decodeTLV) {
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);
}
PrintAndLogEx(INFO, "* Selected."); PrintAndLogEx(INFO, "* Selected.");
PrintAndLogEx(INFO, "\n* Init transaction parameters."); PrintAndLogEx(INFO, "\n* Init transaction parameters.");
@ -1462,8 +1531,9 @@ static int CmdEMVExec(const char *Cmd) {
PrintAndLogEx(INFO, "\n* Read records from AFL."); PrintAndLogEx(INFO, "\n* Read records from AFL.");
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
if (!AFL || !AFL->len) if (!AFL || !AFL->len) {
PrintAndLogEx(WARNING, "WARNING: AFL not found."); PrintAndLogEx(WARNING, "WARNING: AFL not found.");
}
while (AFL && AFL->len) { while (AFL && AFL->len) {
if (AFL->len % 4) { if (AFL->len % 4) {
@ -1584,21 +1654,26 @@ static int CmdEMVExec(const char *Cmd) {
TLVPrintFromTLVLev(cvr, 1); TLVPrintFromTLVLev(cvr, 1);
PrintAndLogEx(INFO, " IDD option id: 0x%02x", IAD->value[8]); PrintAndLogEx(INFO, " IDD option id: 0x%02x", IAD->value[8]);
PrintAndLogEx(INFO, " IDD: %s", sprint_hex(&IAD->value[9], 23)); PrintAndLogEx(INFO, " IDD: %s", sprint_hex(&IAD->value[9], 23));
} else if (IAD->len >= IAD->value[0] + 1) { } else if (IAD->len >= IAD->value[0] + 1) {
PrintAndLogEx(INFO, " Key index: 0x%02x", IAD->value[1]); PrintAndLogEx(INFO, " Key index: 0x%02x", IAD->value[1]);
PrintAndLogEx(INFO, " Crypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]); PrintAndLogEx(INFO, " Crypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]);
PrintAndLogEx(INFO, " CVR: %s", sprint_hex(&IAD->value[3], IAD->value[0] - 2)); PrintAndLogEx(INFO, " CVR: %s", sprint_hex(&IAD->value[3], IAD->value[0] - 2));
struct tlvdb *cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]); struct tlvdb *cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]);
TLVPrintFromTLVLev(cvr, 1); TLVPrintFromTLVLev(cvr, 1);
if (IAD->len >= 8) { if (IAD->len >= 8) {
int iddLen = IAD->value[7]; int iddLen = IAD->value[7];
PrintAndLogEx(NORMAL, " IDD length: %d", iddLen); PrintAndLogEx(NORMAL, " IDD length: %d", iddLen);
if (iddLen >= 1) if (iddLen >= 1) {
PrintAndLogEx(NORMAL, " IDD option id: 0x%02x", IAD->value[8]); PrintAndLogEx(NORMAL, " IDD option id: 0x%02x", IAD->value[8]);
if (iddLen >= 2) }
if (iddLen >= 2) {
PrintAndLogEx(NORMAL, " IDD: %s", sprint_hex(&IAD->value[9], iddLen - 1)); PrintAndLogEx(NORMAL, " IDD: %s", sprint_hex(&IAD->value[9], iddLen - 1));
} }
} }
}
} else { } else {
PrintAndLogEx(WARNING, "WARNING: IAD not found."); PrintAndLogEx(WARNING, "WARNING: IAD not found.");
} }
@ -1611,6 +1686,7 @@ static int CmdEMVExec(const char *Cmd) {
// Mastercard M/CHIP // Mastercard M/CHIP
if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)) { if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)) {
const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL); const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
PrintAndLogEx(INFO, "\n--> Mastercard M/Chip transaction."); PrintAndLogEx(INFO, "\n--> Mastercard M/Chip transaction.");
@ -1621,6 +1697,7 @@ static int CmdEMVExec(const char *Cmd) {
PrintAndLogEx(ERR, "Error GetChallenge. APDU error %4x", sw); PrintAndLogEx(ERR, "Error GetChallenge. APDU error %4x", sw);
dreturn(PM3_ERFTRANS); dreturn(PM3_ERFTRANS);
} }
if (len < 4) { if (len < 4) {
PrintAndLogEx(ERR, "Error GetChallenge. Wrong challenge length %zu", len); PrintAndLogEx(ERR, "Error GetChallenge. Wrong challenge length %zu", len);
dreturn(PM3_ESOFT); dreturn(PM3_ESOFT);
@ -1651,8 +1728,9 @@ static int CmdEMVExec(const char *Cmd) {
dreturn(PM3_ERFTRANS); dreturn(PM3_ERFTRANS);
} }
if (decodeTLV) if (decodeTLV) {
TLVPrintFromBuffer(buf, len); TLVPrintFromBuffer(buf, len);
}
// CDA // CDA
PrintAndLogEx(INFO, "\n* CDA:"); PrintAndLogEx(INFO, "\n* CDA:");
@ -1675,7 +1753,8 @@ static int CmdEMVExec(const char *Cmd) {
if (CID) { if (CID) {
emv_tag_dump(CID, 1); emv_tag_dump(CID, 1);
PrintAndLogEx(INFO, "------------------------------"); PrintAndLogEx(INFO, "------------------------------");
if (CID->len > 0) {
if (CID->len) {
switch (CID->value[0] & EMVAC_AC_MASK) { switch (CID->value[0] & EMVAC_AC_MASK) {
case EMVAC_AAC: case EMVAC_AAC:
PrintAndLogEx(INFO, "Transaction DECLINED."); PrintAndLogEx(INFO, "Transaction DECLINED.");
@ -1725,8 +1804,9 @@ static int CmdEMVExec(const char *Cmd) {
.len = 3, .len = 3,
.value = (uint8_t *)"\x9f\x6a\x04", .value = (uint8_t *)"\x9f\x6a\x04",
}; };
if (!UDOL) if (!UDOL) {
PrintAndLogEx(INFO, "Use default UDOL."); PrintAndLogEx(INFO, "Use default UDOL.");
}
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
if (!udol_data_tlv) { if (!udol_data_tlv) {
@ -1801,6 +1881,7 @@ static int CmdEMVExec(const char *Cmd) {
uint8_t IDDlen = 0; // Issuer discretionary data length uint8_t IDDlen = 0; // Issuer discretionary data length
PrintAndLogEx(INFO, "IAD length: %zu", IAD->len); PrintAndLogEx(INFO, "IAD length: %zu", IAD->len);
PrintAndLogEx(INFO, "VDDlen: %d", VDDlen); PrintAndLogEx(INFO, "VDDlen: %d", VDDlen);
if (VDDlen < IAD->len - 1) { if (VDDlen < IAD->len - 1) {
IDDlen = IAD->value[VDDlen + 1]; IDDlen = IAD->value[VDDlen + 1];
} }
@ -1822,9 +1903,11 @@ static int CmdEMVExec(const char *Cmd) {
PrintAndLogEx(WARNING, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2)); PrintAndLogEx(WARNING, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2));
} }
} }
if (IDDlen) { if (IDDlen) {
PrintAndLogEx(INFO, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen)); PrintAndLogEx(INFO, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen));
} }
} else { } else {
PrintAndLogEx(WARNING, "Issuer Application Data (IAD) not found."); PrintAndLogEx(WARNING, "Issuer Application Data (IAD) not found.");
} }
@ -1898,6 +1981,7 @@ static int CmdEMVExec(const char *Cmd) {
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
PrintAndLogEx(SUCCESS, "\n* Transaction completed."); PrintAndLogEx(SUCCESS, "\n* Transaction completed.");
SetAPDULogging(false);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1928,25 +2012,29 @@ static int CmdEMVScan(const char *Cmd) {
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
bool showAPDU = arg_get_lit(ctx, 1); bool show_apdu = arg_get_lit(ctx, 1);
bool decodeTLV = arg_get_lit(ctx, 2); bool decodeTLV = arg_get_lit(ctx, 2);
bool extractTLVElements = arg_get_lit(ctx, 3); bool extractTLVElements = arg_get_lit(ctx, 3);
bool paramLoadJSON = arg_get_lit(ctx, 4); bool paramLoadJSON = arg_get_lit(ctx, 4);
enum TransactionType TrType = TT_MSD; enum TransactionType TrType = TT_MSD;
if (arg_get_lit(ctx, 6)) if (arg_get_lit(ctx, 6)) {
TrType = TT_QVSDCMCHIP; TrType = TT_QVSDCMCHIP;
if (arg_get_lit(ctx, 7)) }
if (arg_get_lit(ctx, 7)) {
TrType = TT_CDA; TrType = TT_CDA;
if (arg_get_lit(ctx, 8)) }
if (arg_get_lit(ctx, 8)) {
TrType = TT_VSDC; TrType = TT_VSDC;
}
bool GenACGPO = arg_get_lit(ctx, 9); bool GenACGPO = arg_get_lit(ctx, 9);
bool MergeJSON = arg_get_lit(ctx, 10); bool MergeJSON = arg_get_lit(ctx, 10);
Iso7816CommandChannel channel = CC_CONTACTLESS; Iso7816CommandChannel channel = CC_CONTACTLESS;
if (arg_get_lit(ctx, 11)) if (arg_get_lit(ctx, 11)) {
channel = CC_CONTACT; channel = CC_CONTACT;
}
PrintChannel(channel); PrintChannel(channel);
@ -1958,15 +2046,13 @@ static int CmdEMVScan(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
if (!IfPm3Smartcard()) { if (IfPm3Smartcard() == false) {
if (channel == CC_CONTACT) { if (channel == CC_CONTACT) {
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting");
return PM3_EDEVNOTSUPP; return PM3_EDEVNOTSUPP;
} }
} }
SetAPDULogging(showAPDU);
uint8_t AID[APDU_AID_LEN] = {0}; uint8_t AID[APDU_AID_LEN] = {0};
size_t AIDlen = 0; size_t AIDlen = 0;
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
@ -1996,6 +2082,8 @@ static int CmdEMVScan(const char *Cmd) {
root = json_object(); root = json_object();
} }
SetAPDULogging(show_apdu);
// drop field at start // drop field at start
DropFieldEx(channel); DropFieldEx(channel);
@ -2073,7 +2161,7 @@ static int CmdEMVScan(const char *Cmd) {
} }
// EMV SELECT application // EMV SELECT application
SetAPDULogging(showAPDU); SetAPDULogging(show_apdu);
EMVSelectApplication(tlvSelect, AID, &AIDlen); EMVSelectApplication(tlvSelect, AID, &AIDlen);
tlvdb_free(tlvSelect); tlvdb_free(tlvSelect);
@ -2093,7 +2181,7 @@ static int CmdEMVScan(const char *Cmd) {
// EMV SELECT applet // EMV SELECT applet
PrintAndLogEx(INFO, "Selecting AID: " _GREEN_("%s"), sprint_hex_inrow(AID, AIDlen)); PrintAndLogEx(INFO, "Selecting AID: " _GREEN_("%s"), sprint_hex_inrow(AID, AIDlen));
SetAPDULogging(showAPDU); SetAPDULogging(show_apdu);
res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot);
if (res) { if (res) {
@ -2184,10 +2272,12 @@ static int CmdEMVScan(const char *Cmd) {
sfijson = json_path_get(root, "$.Application.Records"); sfijson = json_path_get(root, "$.Application.Records");
} }
if (!json_is_array(sfijson)) { if (!json_is_array(sfijson)) {
PrintAndLogEx(ERR, "Internal logic error. `$.Application.Records` is not an array."); PrintAndLogEx(ERR, "Internal logic error. `$.Application.Records` is not an array.");
break; break;
} }
for (int i = 0; i < AFL->len / 4; i++) { for (int i = 0; i < AFL->len / 4; i++) {
uint8_t SFI = AFL->value[i * 4 + 0] >> 3; uint8_t SFI = AFL->value[i * 4 + 0] >> 3;
uint8_t SFIstart = AFL->value[i * 4 + 1]; uint8_t SFIstart = AFL->value[i * 4 + 1];
@ -2243,11 +2333,11 @@ static int CmdEMVScan(const char *Cmd) {
JsonSaveHex(jsonelm, "Offline", SFIoffline, 1); JsonSaveHex(jsonelm, "Offline", SFIoffline, 1);
struct tlvdb *rsfi = tlvdb_parse_multi(buf, len); struct tlvdb *rsfi = tlvdb_parse_multi(buf, len);
if (extractTLVElements) if (extractTLVElements) {
JsonSaveTLVTree(root, jsonelm, "$.Data", rsfi); JsonSaveTLVTree(root, jsonelm, "$.Data", rsfi);
else } else {
JsonSaveTLVTreeElm(jsonelm, "$.Data", rsfi, true, true, false); JsonSaveTLVTreeElm(jsonelm, "$.Data", rsfi, true, true, false);
}
tlvdb_free(rsfi); tlvdb_free(rsfi);
} }
} }
@ -2273,7 +2363,7 @@ static int CmdEMVScan(const char *Cmd) {
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropFieldEx(channel); DropFieldEx(channel);
SetAPDULogging(false);
if (MergeJSON == false) { if (MergeJSON == false) {
// create unique new name // create unique new name
@ -2356,7 +2446,7 @@ static int CmdEMVRoca(const char *Cmd) {
CLIParserFree(ctx); CLIParserFree(ctx);
PrintChannel(channel); PrintChannel(channel);
if (!IfPm3Smartcard()) { if (IfPm3Smartcard() == false) {
if (channel == CC_CONTACT) { if (channel == CC_CONTACT) {
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting");
return PM3_EDEVNOTSUPP; return PM3_EDEVNOTSUPP;
@ -2395,6 +2485,7 @@ static int CmdEMVRoca(const char *Cmd) {
PrintAndLogEx(ERR, "Can't found any of EMV AID, exiting"); PrintAndLogEx(ERR, "Can't found any of EMV AID, exiting");
tlvdb_free(tlvSelect); tlvdb_free(tlvSelect);
DropFieldEx(channel); DropFieldEx(channel);
SetAPDULogging(false);
return PM3_ERFTRANS; return PM3_ERFTRANS;
} }
@ -2590,6 +2681,7 @@ static int CmdEMVRoca(const char *Cmd) {
} }
out: out:
SetAPDULogging(false);
tlvdb_free(tlvRoot); tlvdb_free(tlvRoot);
DropFieldEx(channel); DropFieldEx(channel);
return ret; return ret;
@ -2685,7 +2777,6 @@ static int CmdEMVReader(const char *Cmd) {
uint8_t log_file_records = 31; uint8_t log_file_records = 31;
struct tlvdb *tlogDB = NULL; struct tlvdb *tlogDB = NULL;
// try getting the LOG TEMPLATE. // try getting the LOG TEMPLATE.
bool log_found = false; bool log_found = false;
bool log_template_found = false; bool log_template_found = false;
@ -2777,8 +2868,9 @@ static int CmdEMVReader(const char *Cmd) {
continue; continue;
} }
if (sw == 0x6A83) if (sw == 0x6A83) {
break; break;
}
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "Transaction log # " _YELLOW_("%u"), i); PrintAndLogEx(INFO, "Transaction log # " _YELLOW_("%u"), i);

View file

@ -37,7 +37,7 @@ void PKISetStrictExecution(bool se) {
strictExecution = se; strictExecution = se;
} }
static const unsigned char empty_tlv_value[] = {}; static const unsigned char empty_tlv_value[] = {0};
static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value}; static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value};
static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, }; static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };

View file

@ -822,9 +822,11 @@ bool emv_tag_dump(const struct tlv *tlv, int level) {
emv_tag_dump_string(tlv, tag, level); emv_tag_dump_string(tlv, tag, level);
break; break;
case EMV_TAG_NUMERIC: case EMV_TAG_NUMERIC:
PrintAndLogEx(NORMAL, "");
emv_tag_dump_numeric(tlv, tag, level); emv_tag_dump_numeric(tlv, tag, level);
break; break;
case EMV_TAG_YYMMDD: case EMV_TAG_YYMMDD:
PrintAndLogEx(NORMAL, "");
emv_tag_dump_yymmdd(tlv, tag, level); emv_tag_dump_yymmdd(tlv, tag, level);
break; break;
case EMV_TAG_CVR: case EMV_TAG_CVR:

View file

@ -22,6 +22,7 @@
#define TLV_H #define TLV_H
#include "common.h" #include "common.h"
#include <stdbool.h>
typedef uint32_t tlv_tag_t; typedef uint32_t tlv_tag_t;
@ -41,7 +42,7 @@ struct tlvdb {
struct tlvdb_root { struct tlvdb_root {
struct tlvdb db; struct tlvdb db;
size_t len; size_t len;
unsigned char buf[0]; unsigned char buf[];
}; };
typedef void (*tlv_cb)(void *data, const struct tlv *tlv, int level, bool is_leaf); typedef void (*tlv_cb)(void *data, const struct tlv *tlv, int level, bool is_leaf);

File diff suppressed because it is too large Load diff

View file

@ -29,15 +29,34 @@
#include "mifare/mifarehost.h" #include "mifare/mifarehost.h"
#include "cmdhfmfu.h" #include "cmdhfmfu.h"
#include "protocols.h" // iclass defines
#include "cmdhftopaz.h" // TOPAZ defines
#include "mifare/mifaredefault.h" // MFP / AES defines
typedef union {
void *v;
uint8_t *bytes;
mfu_dump_t *mfu;
topaz_tag_t *topaz;
iso14a_mf_extdump_t *mfc;
iso14a_mf_dump_ev1_t *mfc_ev1;
} udata_t;
typedef enum { typedef enum {
jsfRaw, jsfRaw,
jsfCardMemory, jsfCardMemory,
jsfMfc_v2,
jsfMfc_v3,
jsfMfuMemory, jsfMfuMemory,
jsfHitag, jsfHitag,
jsfIclass, jsfIclass,
jsf14b, jsf14b,
jsf14b_v2,
jsf15, jsf15,
jsf15_v2,
jsf15_v3,
jsfLegic, jsfLegic,
jsfLegic_v2,
jsfT55x7, jsfT55x7,
jsfT5555, jsfT5555,
jsfMfPlusKeys, jsfMfPlusKeys,
@ -49,6 +68,9 @@ typedef enum {
jsfFido, jsfFido,
jsfFudan, jsfFudan,
jsfTopaz, jsfTopaz,
jsfLto,
jsfCryptorf,
jsfNDEF,
} JSONFileType; } JSONFileType;
typedef enum { typedef enum {
@ -57,8 +79,27 @@ typedef enum {
JSON, JSON,
DICTIONARY, DICTIONARY,
MCT, MCT,
FLIPPER,
} DumpFileType_t; } DumpFileType_t;
typedef enum {
MFU_DF_UNKNOWN,
MFU_DF_PLAINBIN,
MFU_DF_OLDBIN,
MFU_DF_NEWBIN
} mfu_df_e;
typedef enum {
NFC_DF_UNKNOWN,
NFC_DF_MFC,
NFC_DF_MFU,
NFC_DF_MFDES,
NFC_DF_14_3A,
NFC_DF_14_3B,
NFC_DF_14_4A,
NFC_DF_PICOPASS,
} nfc_df_e;
int fileExists(const char *filename); int fileExists(const char *filename);
// set a path in the path list g_session.defaultPaths // set a path in the path list g_session.defaultPaths
@ -80,19 +121,6 @@ char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePath
*/ */
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen); int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen);
/**
* @brief Utility function to save data to a textfile (EML). This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable.
* E.g. dumpdata-15.txt
*
* @param preferredName
* @param data The binary data to write to the file
* @param datalen the length of the data
* @param blocksize the length of one row
* @return 0 for ok, 1 for failz
*/
int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize);
/** STUB /** STUB
* @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that * @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that
* file already exists, it tries with another name until it finds something suitable. * file already exists, it tries with another name until it finds something suitable.
@ -176,6 +204,19 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen);
*/ */
int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen); int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen);
/**
* @brief Utility function to load data from a textfile (NFC). This method takes a preferred name.
* E.g. dumpdata-15.nfc
*
* @param preferredName
* @param data The data array to store the loaded bytes from file
* @param maxdatalen maximum size of data array in bytes
* @param datalen the number of bytes loaded from file
* @param ft
* @return 0 for ok, 1 for failz
*/
int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, nfc_df_e ft);
/** /**
* @brief Utility function to load data from a JSON textfile. This method takes a preferred name. * @brief Utility function to load data from a JSON textfile. This method takes a preferred name.
* E.g. dumpdata-15.json * E.g. dumpdata-15.json
@ -235,12 +276,6 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key
int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen); int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen);
typedef enum {
MFU_DF_UNKNOWN,
MFU_DF_PLAINBIN,
MFU_DF_OLDBIN,
MFU_DF_NEWBIN
} mfu_df_e;
/** /**
* @brief Utility function to check and convert plain mfu dump format to new mfu binary format. * @brief Utility function to check and convert plain mfu dump format to new mfu binary format.
* plain dumps doesn't have any extra data, like version, signature etc. * plain dumps doesn't have any extra data, like version, signature etc.
@ -250,7 +285,8 @@ typedef enum {
* @return PM3_SUCCESS for ok, PM3_ESOFT for fails * @return PM3_SUCCESS for ok, PM3_ESOFT for fails
*/ */
int convert_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose); int convert_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose);
mfu_df_e detect_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose); mfu_df_e detect_mfu_dump_format(uint8_t **dump, bool verbose);
nfc_df_e detect_nfc_dump_format(const char *preferredName, bool verbose);
int searchAndList(const char *pm3dir, const char *ext); int searchAndList(const char *pm3dir, const char *ext);
int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent); int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent);
@ -276,18 +312,33 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
/** STUB /** STUB
* @brief Utility function to save data to three file files (BIN/EML/JSON). * @brief Utility function to save data to three file files (BIN/JSON).
* It also tries to save according to user preferences set dump folder paths. * It also tries to save according to user preferences set dump folder paths.
* E.g. dumpdata.bin * E.g. dumpdata.bin
* E.g. dumpdata.eml
* E.g. dumpdata.json * E.g. dumpdata.json
*
* @param fn * @param fn
* @param d The binary data to write to the file * @param d The binary data to write to the file
* @param n the length of the data * @param n the length of the data
* @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc) * @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc)
* @param blocksize
* @return PM3_SUCCESS if OK * @return PM3_SUCCESS if OK
*/ */
int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize); int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
/** STUB
* @brief Utility function to save data to three file files (BIN/JSON).
* It also tries to save according to user preferences set dump folder paths.
* E.g. dumpdata.bin
* E.g. dumpdata.json
*
* This function is dedicated for MIFARE CLASSIC dumps. Checking for 4 or 7 byte UID in indata.
* Saves the corrected data in the json file
*
* @param fn
* @param d The binary data to write to the file
* @param n the length of the data
* @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc)
* @return PM3_SUCCESS if OK
*/
int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft);
#endif // FILEUTILS_H #endif // FILEUTILS_H

View file

@ -133,6 +133,11 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len); res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000); res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _GREEN_("ok") " )");
} else {
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _RED_("fail") " )");
}
} }
break; break;
} }

View file

@ -108,20 +108,20 @@ typedef struct {
return r->value; \ return r->value; \
} }
MAKE_ENUM_TYPE(uint8_t); MAKE_ENUM_TYPE(uint8_t)
// KSX6924LookupCardType // KSX6924LookupCardType
MAKE_ENUM_CONST(CardType, uint8_t, MAKE_ENUM_CONST(CardType, uint8_t,
{ 0x00, "Pre-paid" }, { 0x00, "Pre-paid" },
{ 0x10, "Post-pay" }, { 0x10, "Post-pay" },
{ 0x20, "Mobile post-pay" }, { 0x20, "Mobile post-pay" },
); )
// KSX6924LookupAlg // KSX6924LookupAlg
MAKE_ENUM_CONST(Alg, uint8_t, MAKE_ENUM_CONST(Alg, uint8_t,
{ 0x00, "SEED" }, { 0x00, "SEED" },
{ 0x10, "3DES" }, { 0x10, "3DES" },
); )
// KSX6924LookupTMoneyIDCenter // KSX6924LookupTMoneyIDCenter
MAKE_ENUM_CONST(TMoneyIDCenter, uint8_t, MAKE_ENUM_CONST(TMoneyIDCenter, uint8_t,
@ -139,20 +139,17 @@ MAKE_ENUM_CONST(TMoneyIDCenter, uint8_t,
{ 0x0b, "EB Card Corporation" }, { 0x0b, "EB Card Corporation" },
{ 0x0c, "Seoul Bus Transport Association" }, { 0x0c, "Seoul Bus Transport Association" },
{ 0x0d, "Cardnet" }, { 0x0d, "Cardnet" },
); )
// KSX6924LookupTMoneyUserCode // KSX6924LookupTMoneyUserCode
MAKE_ENUM_CONST(TMoneyUserCode, uint8_t, MAKE_ENUM_CONST(TMoneyUserCode, uint8_t,
{ 0x01, "Regular/normal" }, { 0x01, "Regular/normal" },
{ 0x02, "Child" }, { 0x02, "Child" },
{ 0x04, "Youth" }, { 0x04, "Youth" },
{ 0x06, "elderly" }, { 0x06, "elderly" },
{ 0x0f, "Test" }, { 0x0f, "Test" },
{ 0xff, "Inactive" }, { 0xff, "Inactive" },
); )
// KSX6924LookupTMoneyDisRate // KSX6924LookupTMoneyDisRate
MAKE_ENUM_CONST(TMoneyDisRate, uint8_t, MAKE_ENUM_CONST(TMoneyDisRate, uint8_t,
@ -163,7 +160,7 @@ MAKE_ENUM_CONST(TMoneyDisRate, uint8_t,
{ 0x20, "Merit, basic" }, { 0x20, "Merit, basic" },
{ 0x21, "Merit, companion" }, { 0x21, "Merit, companion" },
); )
// KSX6924LookupTMoneyTCode // KSX6924LookupTMoneyTCode
MAKE_ENUM_CONST(TMoneyTCode, uint8_t, MAKE_ENUM_CONST(TMoneyTCode, uint8_t,
@ -171,7 +168,7 @@ MAKE_ENUM_CONST(TMoneyTCode, uint8_t,
{ 0x01, "SK Telecom" }, { 0x01, "SK Telecom" },
{ 0x02, "Korea Telecom" }, { 0x02, "Korea Telecom" },
{ 0x03, "LG Uplus" }, { 0x03, "LG Uplus" },
); )
// KSX6924LookupTMoneyCCode // KSX6924LookupTMoneyCCode
MAKE_ENUM_CONST(TMoneyCCode, uint8_t, MAKE_ENUM_CONST(TMoneyCCode, uint8_t,
@ -187,7 +184,7 @@ MAKE_ENUM_CONST(TMoneyCCode, uint8_t,
{ 0x09, "Woori Card" }, { 0x09, "Woori Card" },
{ 0x0a, "Hana SK Card" }, { 0x0a, "Hana SK Card" },
{ 0x0b, "Hyundai Card" }, { 0x0b, "Hyundai Card" },
); )
static const char *KSX6924_UNKNOWN = "Unknown"; static const char *KSX6924_UNKNOWN = "Unknown";
@ -320,7 +317,7 @@ bool KSX6924ParsePurseInfo(const uint8_t *purseInfo, size_t purseLen, struct ksx
// TODO // TODO
return true; return true;
}; }
/** /**
* Prints out a ksx6924_purse_info * Prints out a ksx6924_purse_info
@ -523,7 +520,7 @@ bool KSX6924ParseInitializeCardResponse(const uint8_t *initCardResponse, size_t
// TODO // TODO
return true; return true;
}; }
/** /**
* Prints out a Initialize Card response * Prints out a Initialize Card response

View file

@ -43,6 +43,7 @@
#include "mifare/mad.h" #include "mifare/mad.h"
#include "mifare/aiddesfire.h" #include "mifare/aiddesfire.h"
const CLIParserOption DesfireAlgoOpts[] = { const CLIParserOption DesfireAlgoOpts[] = {
{T_DES, "des"}, {T_DES, "des"},
{T_3DES, "2tdea"}, {T_3DES, "2tdea"},
@ -1749,7 +1750,7 @@ int DesfireFillAppList(DesfireContext_t *dctx, PICCInfo_t *PICCInfo, AppListS ap
memcpy( memcpy(
appList[indx].appDFName, appList[indx].appDFName,
&buf[i * 24 + 1 + 5], &buf[i * 24 + 1 + 5],
// strnlen((char *)&buf[i * 24 + 1 + 5], 16) // str_nlen((char *)&buf[i * 24 + 1 + 5], 16)
16 16
); );
} }
@ -2879,7 +2880,7 @@ int DesfireISOSelect(DesfireContext_t *dctx, DesfireISOSelectControl cntr, uint8
} }
int DesfireISOSelectDF(DesfireContext_t *dctx, char *dfname, uint8_t *resp, size_t *resplen) { int DesfireISOSelectDF(DesfireContext_t *dctx, char *dfname, uint8_t *resp, size_t *resplen) {
return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, strnlen(dfname, 16), resp, resplen); return DesfireISOSelect(dctx, ISSDFName, (uint8_t *)dfname, str_nlen(dfname, 16), resp, resplen);
} }
int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) { int DesfireISOGetChallenge(DesfireContext_t *dctx, DesfireCryptoAlgorithm keytype, uint8_t *resp, size_t *resplen) {

View file

@ -788,11 +788,11 @@ bool desfire_crc32_check(uint8_t *data, const size_t len, uint8_t *crc) {
} }
void iso14443a_crc_append(uint8_t *data, size_t len) { void iso14443a_crc_append(uint8_t *data, size_t len) {
return compute_crc(CRC_14443_A, data, len, data + len, data + len + 1); compute_crc(CRC_14443_A, data, len, data + len, data + len + 1);
} }
void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc) { void iso14443a_crc(uint8_t *data, size_t len, uint8_t *pbtCrc) {
return compute_crc(CRC_14443_A, data, len, pbtCrc, pbtCrc + 1); compute_crc(CRC_14443_A, data, len, pbtCrc, pbtCrc + 1);
} }
bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc) { bool iso14443a_crc_check(uint8_t *data, const size_t len, uint8_t *crc) {

212
client/src/mifare/gen4.c Normal file
View file

@ -0,0 +1,212 @@
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// Common functionality for low/high-frequency GALLAGHER tag encoding & decoding.
//-----------------------------------------------------------------------------
#include "gen4.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "commonutil.h"
#include "util.h"
#include "ui.h"
#include "mifaredefault.h"
#include "comms.h"
#include "cmdhf14a.h"
#include "protocols.h"
#include "mfkey.h"
#include "util_posix.h"
#include "cmdparser.h"
static int mfG4ExCommand(uint8_t cmd, uint8_t *pwd, uint8_t *data, size_t datalen, uint8_t *response, size_t *responselen, bool verbose) {
struct p {
uint8_t cmdheader;
uint8_t pwd[4];
uint8_t command;
uint8_t data[32];
} PACKED payload;
memset(&payload, 0, sizeof(payload));
if (datalen > sizeof(payload.data)) {
return PM3_EINVARG;
}
payload.cmdheader = 0xCF;
payload.command = cmd;
if (pwd != NULL) {
memcpy(payload.pwd, pwd, sizeof(payload.pwd));
}
if (data != NULL && datalen > 0) {
memcpy(payload.data, data, datalen);
}
int resplen = 0;
clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_RAW | ISO14A_NO_RATS | ISO14A_APPEND_CRC, 6 + datalen, 0, (uint8_t *)&payload, 6 + datalen);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if (resp.oldarg[0] != 2) {
if (verbose) PrintAndLogEx(ERR, "No card in the field.");
return PM3_ETIMEOUT;
}
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
if (verbose) {
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
}
} else {
if (verbose) PrintAndLogEx(ERR, "No card in the field.");
return PM3_ETIMEOUT;
}
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
resplen = resp.oldarg[0];
if (!resplen) {
if (verbose) PrintAndLogEx(ERR, "No card response.");
return PM3_EFAILED;
}
resplen = resplen - 2; // 14A CRC
if (resplen < 0)
resplen = 0;
if (resplen > 40) {
if (verbose) PrintAndLogEx(ERR, "Buffer too small(%d).", resplen);
return PM3_EOVFLOW;
}
if (response != NULL)
memcpy(response, resp.data.asBytes, resplen);
if (responselen != NULL)
*responselen = resplen;
return PM3_SUCCESS;
} else {
if (verbose) PrintAndLogEx(ERR, "Reply timeout.");
return PM3_ETIMEOUT;
}
}
int mfG4GetConfig(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) {
uint8_t resp[40] = {0};
size_t resplen = 0;
int res = mfG4ExCommand(GEN4_CMD_DUMP_CONFIG, pwd, NULL, 0, resp, &resplen, verbose);
if (res != PM3_SUCCESS) {
return res;
}
if (data != NULL)
memcpy(data, resp, resplen);
if (datalen != NULL)
*datalen = resplen;
return PM3_SUCCESS;
}
int mfG4GetFactoryTest(uint8_t *pwd, uint8_t *data, size_t *datalen, bool verbose) {
uint8_t resp[40] = {0};
size_t resplen = 0;
int res = mfG4ExCommand(GEN4_CMD_FACTORY_TEST, pwd, NULL, 0, resp, &resplen, verbose);
if (res != PM3_SUCCESS) {
return res;
}
if (data != NULL)
memcpy(data, resp, resplen);
if (datalen != NULL)
*datalen = resplen;
return PM3_SUCCESS;
}
int mfG4ChangePassword(uint8_t *pwd, uint8_t *newpwd, bool verbose) {
uint8_t resp[40] = {0};
size_t resplen = 0;
int res = mfG4ExCommand(GEN4_CMD_CHANGE_PASSWORD, pwd, newpwd, 4, resp, &resplen, verbose);
if (res != PM3_SUCCESS) {
return res;
}
if (resplen != 2 || resp[0] != 0x90 || resp[1] != 0x00)
return PM3_EAPDU_FAIL;
return PM3_SUCCESS;
}
int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) {
struct p {
uint8_t blockno;
uint8_t pwd[4];
uint8_t workFlags;
} PACKED payload;
payload.blockno = blockno;
memcpy(payload.pwd, pwd, sizeof(payload.pwd));
payload.workFlags = workFlags;
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_RDBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_RDBL, &resp, 1500)) {
if (resp.status != PM3_SUCCESS) {
return PM3_EUNDEF;
}
memcpy(data, resp.data.asBytes, MFBLOCK_SIZE);
} else {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
return PM3_SUCCESS;
}
int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data, uint8_t workFlags) {
struct p {
uint8_t blockno;
uint8_t pwd[4];
uint8_t data[MFBLOCK_SIZE];
uint8_t workFlags;
} PACKED payload;
payload.blockno = blockno;
memcpy(payload.pwd, pwd, sizeof(payload.pwd));
memcpy(payload.data, data, sizeof(payload.data));
payload.workFlags = workFlags;
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_WRBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_WRBL, &resp, 1500)) {
if (resp.status != PM3_SUCCESS) {
return PM3_EUNDEF;
}
} else {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
return PM3_SUCCESS;
}

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