From 8fea6cddf722a43701b64a48d5c161c9e13b3af0 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 5 Apr 2020 20:36:39 +1000 Subject: [PATCH 01/21] Concept --- client/Makefile | 3 +- client/emv/emvjson.c | 3 + client/emv/emvjson.h | 1 + client/fileutils.c | 10 ++- client/fileutils.h | 1 + client/proxmark3.c | 8 ++ client/settings.c | 186 +++++++++++++++++++++++++++++++++++++++++++ client/settings.h | 32 ++++++++ 8 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 client/settings.c create mode 100644 client/settings.h diff --git a/client/Makefile b/client/Makefile index a09a033d9..2c5a663c4 100644 --- a/client/Makefile +++ b/client/Makefile @@ -251,7 +251,8 @@ CMDSRCS = crapto1/crapto1.c \ flash.c \ wiegand_formats.c \ wiegand_formatutils.c \ - cardhelper.c + cardhelper.c \ + settings.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c index 75b2e87bf..9b86b38ca 100644 --- a/client/emv/emvjson.c +++ b/client/emv/emvjson.c @@ -94,6 +94,9 @@ int JsonSaveStr(json_t *root, const char *path, const char *value) { return JsonSaveJsonObject(root, path, json_string(value)); }; +int JsonSaveBoolean(json_t *root, const char *path, bool value) { + return JsonSaveJsonObject(root, path, json_boolean(value)); +} int JsonSaveBufAsHexCompact(json_t *elm, const char *path, uint8_t *data, size_t datalen) { char *msg = sprint_hex_inrow(data, datalen); if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ') diff --git a/client/emv/emvjson.h b/client/emv/emvjson.h index 54d97ada8..9b1efb034 100644 --- a/client/emv/emvjson.h +++ b/client/emv/emvjson.h @@ -24,6 +24,7 @@ const char *GetApplicationDataName(tlv_tag_t tag); int JsonSaveJsonObject(json_t *root, const char *path, json_t *value); int JsonSaveStr(json_t *root, const char *path, const char *value); +int JsonSaveBoolean(json_t *root, const char *path, bool value); int JsonSaveInt(json_t *root, const char *path, int value); int JsonSaveBufAsHexCompact(json_t *elm, const char *path, uint8_t *data, size_t datalen); int JsonSaveBufAsHex(json_t *elm, const char *path, uint8_t *data, size_t datalen); diff --git a/client/fileutils.c b/client/fileutils.c index ecf47383f..5ce1f3a6a 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -52,6 +52,9 @@ #define PATH_MAX_LENGTH 200 +extern void JsonLoadSettingsCallback (json_t *root); +extern void JsonSaveSettingsCallback (json_t *root); + struct wave_info_t { char signature[4]; uint32_t filesize; @@ -425,6 +428,9 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } } break; + case jsfSettings: + JsonSaveSettingsCallback (root); + break; default: break; } @@ -863,7 +869,9 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ } *datalen = sptr; } - + if (!strcmp(ctype,"settings")) { + JsonLoadSettingsCallback (root); + } PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), fileName); out: json_decref(root); diff --git a/client/fileutils.h b/client/fileutils.h index 3747e0850..06d3ff20a 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -62,6 +62,7 @@ typedef enum { jsfT55x7, jsfT5555, jsfMfPlusKeys, + jsfSettings, } JSONFileType; typedef enum { diff --git a/client/proxmark3.c b/client/proxmark3.c index 5a6ae23a9..504ae93e5 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -27,6 +27,7 @@ #include "comms.h" #include "fileutils.h" #include "flash.h" +#include "settings.h" static void showBanner(void) { g_printAndLog = PRINTANDLOG_PRINT; @@ -557,6 +558,7 @@ int main(int argc, char *argv[]) { /* initialize history */ using_history(); + #ifdef RL_STATE_READCMD rl_extend_line_buffer(1024); @@ -581,6 +583,12 @@ int main(int argc, char *argv[]) { set_my_executable_path(); set_my_user_directory(); + // Settings + settingsLoad (); + settingsSave (); + printf ("Ver : %s\n",mySettings.version); + // End Settings + for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { diff --git a/client/settings.c b/client/settings.c new file mode 100644 index 000000000..a3571c566 --- /dev/null +++ b/client/settings.c @@ -0,0 +1,186 @@ +/***************************************************************************** + * WARNING + * + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * + ***************************************************************************** + * + * This file is part of loclass. It is a reconstructon of the cipher engine + * used in iClass, and RFID techology. + * + * The implementation is based on the work performed by + * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and + * Milosch Meriac in the paper "Dismantling IClass". + * + * Copyright (C) 2014 Martin Holst Swende + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or, at your option, any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with loclass. If not, see . + * + * + ****************************************************************************/ + +//----------------------------------------------------------------------------- +// Settings Functions +//----------------------------------------------------------------------------- + +#include "settings.h" +#include "comms.h" +#include "emv/emvjson.h" + +// settings_t mySettings; + +// Load all settings into memory (struct) +void settingsLoad (void) +{ + // loadFileJson wants these, so pass in place holder values, though not used + // in settings load; + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + // clear all settings + memset (&mySettings,0x00,sizeof(mySettings)); + + if (loadFileJSON(settingsFilename, &dummyData, sizeof(dummyData), &dummyDL) == PM3_SUCCESS) { + printf ("==> Settings Loaded\n"); + mySettings.loaded = true; + } + + + // Test results + /* + bool os_windows_usecolor; + bool os_windows_useansicolor; + int window_xpos; + int window_ypos; + int window_hsize; + int window_wsize; + */ + printf (" Settings Version : [%s]\n",mySettings.version); + printf (" os_windows_usecolor (bool) : [%d]\n",mySettings.os_windows_usecolor); + printf (" os_windows_useAnsicolor (bool) : [%d]\n",mySettings.os_windows_useansicolor); + printf (" window_xpos (int) : [%d]\n",mySettings.window_xpos); + printf (" window_ypos (int) : [%d]\n",mySettings.window_ypos); + printf (" window_hsize (int) : [%d]\n",mySettings.window_hsize); + printf (" window_wsize (int) : [%d]\n",mySettings.window_wsize); + +} + +// Save all settings from memory (struct) to file +int settingsSave (void) +{ + // Note sure if backup has value ? + char backupFilename[500]; + // if (mySettings.loaded) + + snprintf (backupFilename,sizeof(backupFilename),"%s.bak",settingsFilename); + + if (fileExists (backupFilename)) { + if (remove (backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); + return PM3_ESOFT; + } + } + + if (fileExists (settingsFilename)) { + if (rename (settingsFilename,backupFilename) != 0) { + PrintAndLogEx (FAILED, "Error - could not backup settings file \"%s\" to \"%s\"",settingsFilename,backupFilename); + return PM3_ESOFT; + } + } + + uint8_t dummyData = 0x00; + size_t dummyDL = 0x00; + + // int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen); + + if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS) + PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename); + + return PM3_SUCCESS; +} + +void JsonSaveSettingsCallback (json_t *root) +{ + // extern settings_t mySettings; + + printf ("==> Save Settings\n"); + //JsonSaveStr(root, "FileType", "settings"); + //JsonSaveStr (root,"Test1.Test2","test settings"); + /* + "version": "1.0 Nov 2019", + "os.windows.usecolor": true, + "os.windows.useAnsiColor": true, + "window.xpos": 10, + "window.ypos": 10, + "window.hsize": 300, + "window.wsize": 600 + */ + JsonSaveStr (root,"FileType","settings"); + JsonSaveStr (root,"version","1.0 Nov 2019");//mySettings.version); + JsonSaveBoolean (root,"os.windows.useColor",mySettings.os_windows_usecolor); + JsonSaveBoolean (root,"os.windows.useAnsiColor",mySettings.os_windows_useansicolor); + JsonSaveInt (root,"window.xpos",mySettings.window_xpos); + JsonSaveInt (root,"window.ypos",mySettings.window_ypos); + JsonSaveInt (root,"window.hsize",mySettings.window_hsize); + JsonSaveInt (root,"window.wsize",mySettings.window_wsize); +} + +void JsonLoadSettingsCallback (json_t *root) +{ +// extern settings_t mySettings; + json_error_t up_error = {0}; + int b1; + int i1; + const char *s1; + + if (json_unpack_ex(root, &up_error , 0, "{s:s}","version",&s1) == 0) + strncpy (mySettings.version,s1,sizeof (mySettings.version) - 1); + else + strncpy (mySettings.version,"unknown",sizeof (mySettings.version) - 1); + + // os.windows... + if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.windows.useColor",&b1) == 0) + mySettings.os_windows_usecolor = b1; + else // default + mySettings.os_windows_useansicolor = false; + + if (json_unpack_ex(root,&up_error, 0, "{s:b}","os.windows.useAnsiColor",&b1) == 0) + mySettings.os_windows_useansicolor = b1; + else // default + mySettings.os_windows_useansicolor = false; + + // window... + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.xpos",&i1) == 0) + mySettings.window_xpos = i1; + else // default + mySettings.window_xpos = 0; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.ypos",&i1) == 0) + mySettings.window_ypos = i1; + else // default + mySettings.window_ypos = 0; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.hsize",&i1) == 0) + mySettings.window_hsize = i1; + else // default + mySettings.window_hsize = 0; + if (json_unpack_ex(root,&up_error, 0, "{s:i}","window.wsize",&i1) == 0) + mySettings.window_wsize = i1; + else // default + mySettings.window_wsize = 0; + +} diff --git a/client/settings.h b/client/settings.h new file mode 100644 index 000000000..f0093c207 --- /dev/null +++ b/client/settings.h @@ -0,0 +1,32 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2009 Michael Gernoth +// Copyright (C) 2010 iZsh +// +// 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. +//----------------------------------------------------------------------------- +// Settings Functions +//----------------------------------------------------------------------------- + +#include "fileutils.h" + +#define settingsFilename "settings.json" +typedef struct { + bool loaded; + char version[20]; + bool os_windows_usecolor; + bool os_windows_useansicolor; + int window_xpos; + int window_ypos; + int window_hsize; + int window_wsize; +} settings_t; + +settings_t mySettings; + +void settingsLoad (void); +int settingsSave (void); + +void JsonSaveCallback ( json_t *root); +void JsonLoadCallback ( json_t *root); From aa642d5d1e803b4d4ff7519aa71036d05b692bc8 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 5 Apr 2020 18:27:54 +0200 Subject: [PATCH 02/21] ax --- client/luascripts/Legic_clone.lua | 543 ------------------------------ 1 file changed, 543 deletions(-) delete mode 100644 client/luascripts/Legic_clone.lua diff --git a/client/luascripts/Legic_clone.lua b/client/luascripts/Legic_clone.lua deleted file mode 100644 index 00834c98b..000000000 --- a/client/luascripts/Legic_clone.lua +++ /dev/null @@ -1,543 +0,0 @@ -local utils = require('utils') -local cmds = require('commands') -local getopt = require('getopt') -local ansicolors = require('ansicolors') ---[[ - script to create a clone-dump with new crc - Author: mosci - my Fork: https://github.com/icsom/proxmark3.git - Upstream: https://github.com/Proxmark/proxmark3.git - - 1. read tag-dump, xor byte 22..end with byte 0x05 of the inputfile - 2. write to outfile - 3. set byte 0x05 to newcrc - 4. until byte 0x21 plain like in inputfile - 5. from 0x22..end xored with newcrc - 6. calculate new crc on each segment (needs to know the new MCD & MSN0..2) - - simplest usage: - read a valid legic tag with 'hf legic reader' - save the dump with 'hf legic dump o orig' - place your 'empty' tag on the reader and run 'script run Legic_clone -i orig.bin -w' - you will see some output like: - read 1024 bytes from orig.bin - - place your empty tag onto the PM3 to read and display the MCD & MSN0..2 - the values will be shown below - confirm when ready [y/n] ?y - #db# setting up legic card - #db# MIM 256 card found, reading card ... - #db# Card read, use 'hf legic decode' or - #db# 'data hexsamples 8' to view results - 0b ad c0 de <- !! here you'll see the MCD & MSN of your empty tag, which has to be typed in manually as seen below !! - type in MCD as 2-digit value - e.g.: 00 (default: 79 ) - > 0b - type in MSN0 as 2-digit value - e.g.: 01 (default: 28 ) - > ad - type in MSN1 as 2-digit value - e.g.: 02 (default: d1 ) - > c0 - type in MSN2 as 2-digit value - e.g.: 03 (default: 43 ) - > de - MCD:0b, MSN:ad c0 de, MCC:79 <- this crc is calculated from the MCD & MSN and must match the one on yout empty tag - - wrote 1024 bytes to myLegicClone.hex - enter number of bytes to write? (default: 86 ) - - loaded 1024 samples - #db# setting up legic card - #db# MIM 256 card found, writing 0x00 - 0x01 ... - #db# write successful - ... - #db# setting up legic card - #db# MIM 256 card found, writing 0x56 - 0x01 ... - #db# write successful - proxmark3> - - the default value (number of bytes to write) is calculated over all valid segments and should be ok - just hit enter, wait until write has finished - and your clone should be ready (except there has to be a additional KGH-CRC to be calculated - which credentials are unknown until yet) - - the '-w' switch will only work with my fork - it needs the binary legic_crc8 which is not part of the proxmark3-master-branch - also the ability to write DCF is not possible with the proxmark3-master-branch - but creating dumpfile-clone files will be possible (without valid segment-crc - this has to done manually with) - - - (example) Legic-Prime Layout with 'Kaba Group Header' - +----+----+----+----+----+----+----+----+ - 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | - +----+----+----+----+----+----+----+----+ - 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| - +----+----+----+----+----+----+----+----+ - 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| - +----+----+----+----+----+----+----+----+ - 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| - +----+----+----+----+----+----+----+----+ - 0x20|UID1|UID2|kghC| - +----+----+----+ - - MCD= ManufacturerID (1 Byte) - MSN0..2= ManufactureSerialNumber (3 Byte) - MCC= CRC (1 Byte) calculated over MCD,MSN0..2 - DCF= DecrementalField (2 Byte) 'credential' (enduser-Tag) seems to have always DCF-low=0x60 DCF-high=0xea - Bck0..5= Backup (6 Byte) Bck0 'dirty-flag', Bck1..5 SegmentHeader-Backup - BCC= BackupCRC (1 Byte) CRC calculated over Bck1..5 - Seg0..3= SegmentHeader (on MIM 4 Byte ) - SegC= SegmentCRC (1 Byte) calculated over MCD,MSN0..2,Seg0..3 - Stp0..n= Stamp0... (variable length) length = Segment-Len - UserData - 1 - UID0..n= UserDater (variable length - with KGH hex 0x00-0x63 / dec 0-99) length = Segment-Len - WRP - WRC - 1 - kghC= KabaGroupHeader (1 Byte + addr 0x0c must be 0x11) - as seen on this example: addr 0x05..0x08 & 0x0c must have been set to this values - otherwise kghCRC will not be created by a official reader (not accepted) ---]] - -copyright = '' -author = 'Mosci' -version = 'v1.0.2' -desc = [[ -This is a script which creates a clone-dump of a dump from a Legic Prime Tag (MIM256 or MIM1024) -(created with 'hf legic dump f my_dump') -]] -example = [[ - script run legic_clone -i my_dump.bin -o my_clone.bin -c f8 - script run legic_clone -i my_dump.bin -d -s -]] -usage = [[ -script run legic_clone -h -i -o -c -d -s -w -]] -arguments = [[ -required : - -i (file to read data from, must be in binary format (*.bin)) - -optional : - -h - Help text - -o - requires option -c to be given - -c - requires option -o to be given - -d - Display content of found Segments - -s - Display summary at the end - -w - write directly to Tag - a file myLegicClone.bin will be generated also - - e.g.: - hint: using the CRC '00' will result in a plain dump ( -c 00 ) -]] - -local bxor = bit32.bxor - --- we need always 2 digits -local function prepend_zero(s) - if (string.len(s) == 1) then - return '0' .. s - else - if (string.len(s) == 0) then - return '00' - else - return s - end - 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 - --- read LEGIC data -local function readlegicdata( offset, length, iv ) - -- Read data - local command = Command:newMIX{ - cmd = cmds.CMD_HF_LEGIC_READER - , arg1 = offset - , arg2 = length - , arg3 = iv - , data = nil - } - local result, err = command:sendMIX() - if not result then return oops(err) end - -- result is a packed data structure, data starts at offset 33 - return result -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 - --- Check availability of file -local function file_check(file_name) - local file_found = io.open(file_name, "r") - if not file_found then - file_found = false - else - file_found = true - end - return file_found -end - ---- xor-wrapper --- xor all from addr 0x22 (start counting from 1 => 23) -local function xorme(hex, xor, index) - if ( index >= 23 ) then - return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) - else - return hex - end -end - --- read input-file into array -local function getInputBytes(infile) - local line - local bytes = {} - - local fhi,err = io.open(infile,"rb") - if err then print("OOps ... faild to read from file ".. infile); return false; end - - str = fhi:read("*all") - for c in (str or ''):gmatch'.' do - bytes[#bytes+1] = ('%02x'):format(c:byte()) - end - - fhi:close() - - print("\nread ".. #bytes .." bytes from ".. infile) - return bytes -end - --- write to file -local function writeOutputBytes(bytes, outfile) - local fho,err = io.open(outfile,"wb") - if err then print("OOps ... faild to open output-file ".. outfile); return false; end - - for i = 1, #bytes do - fho:write(string.char(tonumber(bytes[i],16))) - end - fho:close() - print("\nwrote ".. #bytes .." bytes to " .. outfile) - return true -end - --- xore certain bytes -local function xorBytes(inBytes, crc) - local bytes = {} - for index = 1, #inBytes do - bytes[index] = xorme(inBytes[index], crc, index) - end - if (#inBytes == #bytes) then - -- replace crc - bytes[5] = string.sub(crc,-2) - return bytes - else - print("error: byte-count missmatch") - return false - end -end - --- get raw segment-data -function getSegmentData(bytes, start, index) - local raw, len, valid, last, wrp, wrc, rd, crc - local segment = {} - segment[0] = bytes[start]..' '..bytes[start+1]..' '..bytes[start+2]..' '..bytes[start+3] - -- flag = high nibble of byte 1 - segment[1] = string.sub(bytes[start+1],0,1) - - -- valid = bit 6 of byte 1 - segment[2] = tonumber(bit32.extract('0x'..bytes[start+1],6,1),16) - - -- last = bit 7 of byte 1 - segment[3] = tonumber(bit32.extract('0x'..bytes[start+1],7,1),16) - - -- len = (byte 0)+(bit0-3 of byte 1) - segment[4] = tonumber(('%03x'):format(tonumber(bit32.extract('0x'..bytes[start+1],0,3),16)..tonumber(bytes[start],16)),16) - - -- wrp (write proteted) = byte 2 - segment[5] = tonumber(bytes[start+2]) - - -- wrc (write control) - bit 4-6 of byte 3 - segment[6] = tonumber(bit32.extract('0x'..bytes[start+3],4,3),16) - - -- rd (read disabled) - bit 7 of byte 3 - segment[7] = tonumber(bit32.extract('0x'..bytes[start+3],7,1),16) - - -- crc byte 4 - segment[8] = bytes[start+4] - - -- segment index - segment[9] = index - - -- # crc-byte - segment[10] = start+4 - return segment -end - ---- Kaba Group Header --- checks if a segment does have a kghCRC --- returns boolean false if no kgh has being detected or the kghCRC if a kgh was detected -function CheckKgh(bytes, segStart, segEnd) - if (bytes[8]=='9f' and bytes[9]=='ff' and bytes[13]=='11') then - local i - local data = {} - segStart = tonumber(segStart, 10) - segEnd = tonumber(segEnd, 10) - local dataLen = segEnd-segStart-5 - --- gather creadentials for verify - local WRP = bytes[(segStart+2)] - local WRC = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],4,3),16)) - local RD = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],7,1),16)) - local XX = "00" - cmd = bytes[1]..bytes[2]..bytes[3]..bytes[4]..WRP..WRC..RD..XX - for i = (segStart+5), (segStart+5+dataLen-2) do - cmd = cmd..bytes[i] - end - local KGH = ("%02x"):format(utils.Crc8Legic(cmd)) - if (KGH == bytes[segEnd-1]) then - return KGH - else - return false - end - else - return false - end -end - --- get only the addresses of segemnt-crc's and the length of bytes -function getSegmentCrcBytes(bytes) - local start = 23 - local index = 0 - local crcbytes = {} - repeat - seg = getSegmentData(bytes,start,index) - crcbytes[index] = seg[10] - start = start + seg[4] - index = index + 1 - until (seg[3] == 1 or tonumber(seg[9]) == 126 ) - crcbytes[index] = start - return crcbytes -end - --- print segment-data (hf legic info like) -function displaySegments(bytes) - --display segment header(s) - start = 23 - index = '00' - - --repeat until last-flag ist set to 1 or segment-index has reached 126 - repeat - wrc = '' - wrp = '' - pld = '' - Seg = getSegmentData(bytes, start, index) - KGH = CheckKgh(bytes, start, (start+tonumber(Seg[4],10))) - printSegment(Seg) - - -- wrc - if (Seg[6] > 0) then - print("WRC protected area:") - -- length of wrc = wrc - for i=1, Seg[6] do - -- starts at (segment-start + segment-header + segment-crc)-1 - wrc = wrc..bytes[(start+4+1+i)-1]..' ' - end - print(wrc) - elseif (Seg[5] > 0) then - print("Remaining write protected area:") - -- length of wrp = (wrp-wrc) - for i=1, (Seg[5]-Seg[6]) do - -- starts at (segment-start + segment-header + segment-crc + wrc)-1 - wrp = wrp..bytes[(start+4+1+Seg[6]+i)-1]..' ' - end - print(wrp) - end - - -- payload - print("Remaining segment payload:") - --length of payload = segment-len - segment-header - segment-crc - wrp -wrc - for i=1, (Seg[4]-4-1-Seg[5]-Seg[6]) do - -- starts at (segment-start + segment-header + segment-crc + segment-wrp + segemnt-wrc)-1 - pld = pld..bytes[(start+4+1+Seg[5]+Seg[6]+i)-1]..' ' - end - print(pld) - if (KGH) then - print("'Kaba Group Header' detected") - end - start = start+Seg[4] - index = prepend_zero(tonumber(Seg[9])+1) - - until (Seg[3] == 1 or tonumber(Seg[9]) == 126 ) -end - --- print Segment values -function printSegment(SegmentData) - res = "\nSegment "..SegmentData[9]..": " - res = res.. "raw header="..SegmentData[0]..", " - res = res.. "flag="..SegmentData[1].." (valid="..SegmentData[2].." last="..SegmentData[3].."), " - res = res.. "len="..("%04d"):format(SegmentData[4])..", " - res = res.. "WRP="..prepend_zero(SegmentData[5])..", " - res = res.. "WRC="..prepend_zero(SegmentData[6])..", " - res = res.. "RD="..SegmentData[7]..", " - res = res.. "crc="..SegmentData[8] - print(res) -end - --- write clone-data to tag -function writeToTag(plainBytes) - local SegCrcs = {} - local output - local readbytes - if(utils.confirm("\nplace your empty tag onto the PM3 to restore the data of the input file\nthe CRCs will be calculated as needed\n confirm when ready") == false) then - return - end - - readbytes = readlegicdata(0, 4, 0x55) - -- gather MCD & MSN from new Tag - this must be enterd manually - print("\nthese are the MCD MSN0 MSN1 MSN2 from the Tag that has being read:") - - plainBytes[1] = ('%02x'):format(readbytes:byte(33)) - plainBytes[2] = ('%02x'):format(readbytes:byte(34)) - plainBytes[3] = ('%02x'):format(readbytes:byte(35)) - plainBytes[4] = ('%02x'):format(readbytes:byte(36)) - - MCD = plainBytes[1] - MSN0 = plainBytes[2] - MSN1 = plainBytes[3] - MSN2 = plainBytes[4] - -- calculate crc8 over MCD & MSN - cmd = MCD..MSN0..MSN1..MSN2 - MCC = ("%02x"):format(utils.Crc8Legic(cmd)) - print("MCD:"..MCD..", MSN:"..MSN0.." "..MSN1.." "..MSN2..", MCC:"..MCC) - - -- calculate new Segment-CRC for each valid segment - SegCrcs = getSegmentCrcBytes(plainBytes) - for i=0, (#SegCrcs-1) do - -- SegCrcs[i]-4 = address of first byte of segmentHeader (low byte segment-length) - segLen = tonumber(("%1x"):format(tonumber(bit32.extract("0x"..plainBytes[(SegCrcs[i]-3)],0,3),16))..("%02x"):format(tonumber(plainBytes[SegCrcs[i]-4],16)),16) - segStart = (SegCrcs[i]-4) - segEnd = (SegCrcs[i]-4+segLen) - KGH = CheckKgh(plainBytes,segStart,segEnd) - if (KGH) then - print("'Kaba Group Header' detected - re-calculate...") - end - cmd = MCD..MSN0..MSN1..MSN2..plainBytes[SegCrcs[i]-4]..plainBytes[SegCrcs[i]-3]..plainBytes[SegCrcs[i]-2]..plainBytes[SegCrcs[i]-1] - plainBytes[SegCrcs[i]] = ("%02x"):format(utils.Crc8Legic(cmd)) - end - - -- apply MCD & MSN to plain data - plainBytes[1] = MCD - plainBytes[2] = MSN0 - plainBytes[3] = MSN1 - plainBytes[4] = MSN2 - plainBytes[5] = MCC - - -- prepare plainBytes for writing (xor plain data with new MCC) - bytes = xorBytes(plainBytes, MCC) - - -- write data to file - if (writeOutputBytes(bytes, "myLegicClone.bin")) then - -- write pm3-buffer to Tag - cmd = ('hf legic restore f myLegicClone') - core.console(cmd) - end -end - --- main function -function main(args) - -- some variables - local i = 0 - local oldcrc, newcrc, infile, outfile - local bytes = {} - local segments = {} - - -- parse arguments for the script - for o, a in getopt.getopt(args, 'hwsdc:i:o:') do - -- output file - if o == 'o' then - outfile = a - ofs = true - if (file_check(a)) then - local answer = utils.confirm('\nthe output-file '..a..' already exists!\nthis will delete the previous content!\ncontinue?') - if (answer==false) then return oops('quiting') end - end - end - -- input file - if o == 'i' then - infile = a - if (file_check(infile)==false) then - return oops('input file: '..infile..' not found') - else - bytes = getInputBytes(infile) - oldcrc = bytes[5] - ifs = true - if (bytes == false) then return oops('couldnt get input bytes') end - end - i = i+1 - end - -- new crc - if o == 'c' then - newcrc = a:lower() - ncs = true - end - -- display segments switch - if o == 'd' then ds = true; end - -- display summary switch - if o == 's' then ss = true; end - -- write to tag switch - if o == 'w' then ws = true; end - -- help - if o == 'h' then return help() end - end - - if (not ifs) then return oops('option -i is required but missing') end - - -- bytes to plain - bytes = xorBytes(bytes, oldcrc) - - -- show segments (works only on plain bytes) - if (ds) then - print("+------------------------------------------- Segments -------------------------------------------+") - displaySegments(bytes); - end - - if (ofs and ncs) then - -- xor bytes with new crc - newBytes = xorBytes(bytes, newcrc) - -- write output - if (writeOutputBytes(newBytes, outfile)) then - -- show summary if requested - if (ss) then - -- information - res = "\n+-------------------------------------------- Summary -------------------------------------------+" - res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" - res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc,-2) - res = res .."\nyou may load the new file with: hf legic eload "..outfile - res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" - res = res .."\nafter writing this dump to a tag!" - res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3,Segment-Header0..3" - res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" - res = res .."\nhf legic crc d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." u "..newcrc.." c 8" - -- this can not be calculated without knowing the new MCD, MSN0..2 - print(res) - end - end - else - if (ss) then - -- show why the output-file was not written - print("\nnew file not written - some arguments are missing ..") - print("output file: ".. (ofs and outfile or "not given")) - print("new crc: ".. (ncs and newcrc or "not given")) - end - end - -- write to tag - if (ws and ( #bytes == 1024 or #bytes == 256)) then - writeToTag(bytes) - end -end - --- call main with arguments -main(args) From 25bcd6b89cbbd091d6a81a79d57c5cfc008d48d6 Mon Sep 17 00:00:00 2001 From: Bjoern Kerler Date: Sun, 5 Apr 2020 21:33:41 +0200 Subject: [PATCH 03/21] Improve 14444-3a card detection --- client/cmdhf14a.c | 353 +++++++++++++++++++++++++++++++--------------- 1 file changed, 243 insertions(+), 110 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index a3ee49503..74260e9f6 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1245,6 +1245,122 @@ int CmdHF14A(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } +static void printTag(char *tag) { + PrintAndLogEx(SUCCESS, _YELLOW_(" %s"), tag); +} + + +typedef enum { + mtNone = 0, + mtClassic = 1, + mtMini = 2, + mtDESFire = 4, + mtPlus = 8, + mtUltralight = 16, + mtOther = 32 +} nxp_mifare_type; + +// According to NXP AN10833 Rev 3.6 MIFARE Type Identification, Table 6 +int detect_nxp_card(uint8_t sak, uint16_t atqa) { + int type = mtNone; + + if (sak == 0x00) { + printTag("MIFARE Ultralight C / Ultralight CL2"); + type = mtUltralight; + } + + if (sak == 0x01) { + printTag("TNP3xxx (Activision Game Appliance)"); + type = mtOther; + } + if ((sak & 0x04) == 0x04) { + printTag("Any MIFARE CL1"); + type |= mtDESFire; + } + if ((sak & 0x08) == 0x08) { + printTag("MIFARE Classic 1K / Classic 1K CL2"); + printTag("MIFARE Plus 2K / Plus EV1 2K"); + printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 2K"); + type |= mtClassic; + type |= mtPlus; + } + if ((sak & 0x09) == 0x09) { + printTag("MIFARE Mini 0.3K / Mini CL2 0.3K"); + type |= mtMini; + } + if ((sak & 0x10) == 0x10) { + printTag("MIFARE Plus 2K / Plus CL2 2K"); + type |= mtPlus; + } + if ((sak & 0x11) == 0x11) { + printTag("MIFARE Plus 4K / Plus CL2 4K"); + type |= mtPlus; + } + if ((sak & 0x18) == 0x18) { + if (atqa == 0x0042) { + printTag("MIFARE Plus 4K / Plus EV1 4K"); + printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K"); + type |= mtPlus; + } else { + printTag("MIFARE Classic 4K / Classic 4K CL2"); + type |= mtClassic; + } + + } + if ((sak & 0x20) == 0x20) { + if (atqa == 0x0344) { + printTag("MIFARE DESFire EV1 2K/4K/8K / DESFire EV1 CL2 2K/4K/8K"); + type |= mtDESFire; + } else { + printTag("MIFARE Plus 2K / Plus EV1 2K"); + printTag("MIFARE Plus 4K / Plus EV1 4K"); + printTag("MIFARE Plus CL2 2K / Plus CL2 EV1 4K"); + printTag("MIFARE Plus CL2 4K / Plus CL2 EV1 4K"); + type |= mtPlus; + } + } + if ((sak & 0x24) == 0x24) { + if (atqa == 0x0344) { + printTag("MIFARE DESFire CL1 / DESFire EV1 CL1"); + type |= mtDESFire; + } + } + if ((sak & 0x28) == 0x28) { + if (atqa == 0x0344) { + printTag("MIFARE DESFire CL1 / DESFire EV1 CL1"); + type |= mtDESFire; + } + } + return type; +} + +typedef struct { + uint8_t uid0; + uint8_t uid1; + char *desc; +} uidname; + +const uidname uidmap[] = { + // UID0, UID1, TEXT + {0x02, 0x03, "ST SRIX4K"}, + {0x05, 0x1E, "my-d(tm) move SLE66r01P"}, + {0x05, 0x20, "my-d(tm) move SLE66r01P"}, + {0x11, 0x22, "NTAG21x Modifiable"}, + {0x00, 0x00, "None"} +}; + +void getTagLabel(uint8_t uid0, uint8_t uid1) { + int i = 0; + while (uidmap[i].uid0 != 0x00) { + if ((uidmap[i].uid0 == uid0) && (uidmap[i].uid1 == uid1)) { + PrintAndLogEx(SUCCESS, _YELLOW_(" %s"), uidmap[i].desc); + return; + } + i += 1; + } + return; +} + int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); @@ -1290,97 +1406,110 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]); bool isMifareClassic = true; - bool isMifareDesfire = false; + bool isMifareDESFire = false; bool isMifarePlus = false; bool isMifareUltralight = false; - - switch (card.sak) { - case 0x00: - isMifareClassic = false; - - // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) - DropField(); - - uint32_t tagT = GetHF14AMfU_Type(); - if (tagT != UL_ERROR) { - ul_print_type(tagT, 0); - isMifareUltralight = true; - } else { - PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)"); - } - - // reconnect for further tests - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); - WaitForResponse(CMD_ACK, &resp); - - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - - if (select_status == 0) { - DropField(); - return select_status; - } - break; - case 0x01: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP TNP3xxx Activision Game Appliance")); - break; - case 0x04: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE (various !DESFire !DESFire EV1)")); - isMifareClassic = false; - isMifareDesfire = true; - break; - case 0x08: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1")); - break; - case 0x09: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Mini 0.3k")); - break; - case 0x0A: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("FM11RF005SH (Shanghai Metro)")); - break; - case 0x10: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 2k SL2")); - isMifarePlus = true; - break; - case 0x11: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 4k SL2")); - isMifarePlus = true; - break; - case 0x18: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1")); - break; - case 0x20: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41")); - isMifareClassic = false; - isMifareDesfire = true; - isMifarePlus = true; - break; - case 0x24: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire | DESFire EV1")); - isMifareClassic = false; - isMifareDesfire = true; - break; - case 0x28: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("JCOP31 or JCOP41 v2.3.1")); - break; - case 0x38: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Nokia 6212 or 6131 MIFARE CLASSIC 4K")); - break; - case 0x88: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Infineon MIFARE CLASSIC 1K")); - break; - case 0x98: - PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Gemplus MPCOS")); - break; - default: - ; - } - + int nxptype = mtNone; // Double & triple sized UID, can be mapped to a manufacturer. + if (card.uidlen <= 4) { + nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0])); + if ((nxptype & mtClassic) == mtClassic) isMifareClassic = true; + else isMifareClassic = false; + if ((nxptype & mtDESFire) == mtDESFire) { + isMifareDESFire = true; + } else { + isMifareDESFire = false; + } + if ((nxptype & mtPlus) == mtPlus) isMifarePlus = true; + else isMifarePlus = false; + if ((nxptype & mtUltralight) == mtUltralight) isMifareUltralight = true; + else isMifareUltralight = false; + if ((nxptype & mtOther) == mtOther) isMifareClassic = true; + } if (card.uidlen > 4) { PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); + + PrintAndLogEx(SUCCESS, "Possible Type:"); + switch (card.uid[0]) { + case 0x04: // NXP + nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0])); + if ((nxptype & mtClassic) == mtClassic) isMifareClassic = true; + else isMifareClassic = false; + if ((nxptype & mtDESFire) == mtDESFire) { + isMifareDESFire = true; + } else { + isMifareDESFire = false; + } + if ((nxptype & mtPlus) == mtPlus) isMifarePlus = true; + else isMifarePlus = false; + if ((nxptype & mtUltralight) == mtUltralight) isMifareUltralight = true; + else isMifareUltralight = false; + if ((nxptype & mtOther) == mtOther) isMifareClassic = true; + break; + case 0x05: // Infineon + if ((card.uid[1] & 0xF0) == 0x30) { + printTag("my-d(tm) move lean SLE 66R01PN"); + } else if ((card.uid[1] & 0xF0) == 0x70) { + printTag("my-d(tm) move lean SLE 66R01L"); + } + + if (card.sak == 0x88) { + printTag("Infineon MIFARE CLASSIC 1K"); + } + getTagLabel(card.uid[0], card.uid[1]); + break; + default: + getTagLabel(card.uid[0], card.uid[1]); + switch (card.sak) { + case 0x00: + isMifareClassic = false; + + // ******** is card of the MFU type (UL/ULC/NTAG/ etc etc) + DropField(); + + uint32_t tagT = GetHF14AMfU_Type(); + if (tagT != UL_ERROR) { + ul_print_type(tagT, 0); + isMifareUltralight = true; + printTag("MIFARE Ultralight/C/NTAG Compatible"); + } else { + printTag("Possible AZTEK (iso14443a compliant)"); + } + + // reconnect for further tests + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + WaitForResponse(CMD_ACK, &resp); + + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS + + if (select_status == 0) { + DropField(); + return select_status; + } + break; + case 0x0A: + printTag("FM11RF005SH (Shanghai Metro)"); + break; + case 0x20: + printTag("JCOP 31/41"); + break; + case 0x28: + printTag("JCOP31 or JCOP41 v2.3.1"); + break; + case 0x38: + printTag("Nokia 6212 or 6131"); + break; + case 0x98: + printTag("Gemplus MPCOS"); + break; + default: + break; + } + break; + } } // try to request ATS even if tag claims not to support it @@ -1455,12 +1584,14 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { ); pos++; } + if (tc1) { PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported", (card.ats[pos] & 0x01) ? "" : " NOT", (card.ats[pos] & 0x02) ? "" : " NOT"); pos++; } + if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) { const char *tip = ""; if (card.ats[0] - pos >= 7) { @@ -1477,14 +1608,14 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { switch (card.ats[pos + 2] & 0xf0) { case 0x10: PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); - isMifareDesfire = true; + isMifareDESFire = true; isMifareClassic = false; isMifarePlus = false; break; case 0x20: PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); isMifarePlus = true; - isMifareDesfire = false; + isMifareDESFire = false; isMifareClassic = false; break; } @@ -1607,37 +1738,39 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); } - detect_classic_magic(); - - if (isMifareClassic) { - int res = detect_classic_prng(); - if (res == 1) - PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak")); - else if (res == 0) - PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard")); - else - PrintAndLogEx(FAILED, "prng detection: " _RED_("fail")); - - if (do_nack_test) - detect_classic_nackbug(false); - - res = detect_classic_static_nonce(); - if (res == 1) - PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes") ); - if (res == 2 && verbose) - PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail")); - } - if (isMifareUltralight) { PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`")); } if (isMifarePlus) { PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`")); } - if (isMifareDesfire) { + if (isMifareDESFire) { PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`")); } + if (((card.sak & 0x08) == 0x08) || ((card.sak & 0x18) == 0x18)) { + detect_classic_magic(); + + if (isMifareClassic) { + int res = detect_classic_prng(); + if (res == 1) + PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak")); + else if (res == 0) + PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard")); + else + PrintAndLogEx(FAILED, "prng detection: " _RED_("fail")); + + if (do_nack_test) + detect_classic_nackbug(false); + + res = detect_classic_static_nonce(); + if (res == 1) + PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes")); + if (res == 2 && verbose) + PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail")); + + } + } return select_status; } From ca51fee02e4f7a56727752103362ee0a5dbd53cf Mon Sep 17 00:00:00 2001 From: Bjoern Kerler Date: Mon, 6 Apr 2020 00:00:53 +0200 Subject: [PATCH 04/21] Add ST uid infos --- client/cmdhf14a.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 74260e9f6..f737ff485 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1342,9 +1342,22 @@ typedef struct { const uidname uidmap[] = { // UID0, UID1, TEXT - {0x02, 0x03, "ST SRIX4K"}, - {0x05, 0x1E, "my-d(tm) move SLE66r01P"}, - {0x05, 0x20, "my-d(tm) move SLE66r01P"}, + {0x02, 0x00, "SR176"}, + {0x02, 0x03, "SRIX4K"}, + {0x02, 0x0C, "SRT512"}, + {0x02, 0x0F, "SRI2K"}, + {0x02, 0x1B, "25TB512-AC"}, + {0x02, 0x3D, "SRIX4K"}, + {0x02, 0x3F, "25TB02K"}, + {0x02, 0x4D, "SRIX512"}, + {0x02, 0x6D, "SRI512"}, + {0x02, 0x7D, "SRI4K"}, + {0x02, 0x84, "M24SR64-Y"}, + {0x02, 0xA3, "25TA02KB-P"}, + {0x02, 0xC4, "25TA64K"}, + {0x02, 0xE3, "25TA02KB"}, + {0x02, 0xE4, "25TA512B"}, + {0x02, 0xF3, "25TA02KB-D"}, {0x11, 0x22, "NTAG21x Modifiable"}, {0x00, 0x00, "None"} }; @@ -1447,8 +1460,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if ((nxptype & mtOther) == mtOther) isMifareClassic = true; break; case 0x05: // Infineon - if ((card.uid[1] & 0xF0) == 0x30) { - printTag("my-d(tm) move lean SLE 66R01PN"); + if ((card.uid[1] & 0xF0) == 0x10) { + printTag("my-d(tm) command set SLE 66R04/16/32P, SLE 66R04/16/32S"); + } else if ((card.uid[1] & 0xF0) == 0x20) { + printTag("my-d(tm) command set SLE 66R01/16/32P (Type 2 Tag)"); + } else if ((card.uid[1] & 0xF0) == 0x30) { + printTag("my-d(tm) move lean SLE 66R01P/66R01PN"); } else if ((card.uid[1] & 0xF0) == 0x70) { printTag("my-d(tm) move lean SLE 66R01L"); } From 4df7c3bf03b061cfdd1b83466c8335af5af677d7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:05:02 +0200 Subject: [PATCH 05/21] coverity fixes --- client/cmdhflegic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 69df2526c..8fc3ed357 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -1013,6 +1013,7 @@ static int CmdLegicDump(const char *Cmd) { saveFile(filename, ".bin", data, readlen); saveFileEML(filename, data, readlen, 8); saveFileJSON(filename, jsfLegic, data, readlen); + free(data); return PM3_SUCCESS; } @@ -1076,7 +1077,7 @@ static int CmdLegicRestore(const char *Cmd) { } if (card.cardsize != numofbytes) { - PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%zu != %u]", card.cardsize, numofbytes); + PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%u != %zu]", card.cardsize, numofbytes); free(data); return PM3_EFILE; } From e0ff7d03387a663852c41010a9673fd7486e451d Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:16:32 +0200 Subject: [PATCH 06/21] cryptorf skeleton cmds -WIP- --- client/cmdhfcryptorf.c | 449 +++++++++++++++++++++++++++++++++++++++++ client/cmdhfcryptorf.h | 20 ++ 2 files changed, 469 insertions(+) create mode 100644 client/cmdhfcryptorf.c create mode 100644 client/cmdhfcryptorf.h diff --git a/client/cmdhfcryptorf.c b/client/cmdhfcryptorf.c new file mode 100644 index 000000000..76441596f --- /dev/null +++ b/client/cmdhfcryptorf.c @@ -0,0 +1,449 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 iceman +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency CryptoRF commands (ISO14443B) +//----------------------------------------------------------------------------- + +#include "cmdhfcryptorf.h" + +#include +#include "fileutils.h" + +#include "cmdparser.h" // command_t +#include "comms.h" // clearCommandBuffer +#include "cmdtrace.h" +#include "crc16.h" +#include "cmdhf14a.h" +#include "protocols.h" // definitions of ISO14B protocol + +#define TIMEOUT 2000 +static int CmdHelp(const char *Cmd); + +static int usage_hf_cryptorf_info(void) { + PrintAndLogEx(NORMAL, "Usage: hf cryptorf info [h] [v]\n" + "Options:\n" + " h this help\n" + " v verbose\n" + "\n" + "Example:\n" + _YELLOW_(" hf cryptorf info") + ); + return PM3_SUCCESS; +} +static int usage_hf_cryptorf_reader(void) { + PrintAndLogEx(NORMAL, "Usage: hf cryptorf reader [h] [v]\n" + "Options:\n" + " h this help\n" + " v verbose\n" + "\n" + "Example:\n" + _YELLOW_(" hf cryptorf reader") + ); + return PM3_SUCCESS; +} +static int usage_hf_cryptorf_sniff(void) { + PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer\n" + "Buffer accessible from command " _YELLOW_("'hf list cryptorf'") "\n" + "Usage: hf cryptorf sniff [h]\n" + "Options:\n" + " h this help\n" + "\n" + "Example:\n" + _YELLOW_(" hf cryptorf sniff") + ); + return PM3_SUCCESS; +} +static int usage_hf_cryptorf_sim(void) { + PrintAndLogEx(NORMAL, "Emulating CryptoRF tag with 4 UID / PUPI\n" + "Usage: hf cryptorf sim [h] [u ]\n" + "Options:\n" + " h this help\n" + " u 4byte UID/PUPI\n" + "\n" + "Example:\n" + _YELLOW_(" hf cryptorf sim") + ); + return PM3_SUCCESS; +} +static int usage_hf_cryptorf_dump(void) { + PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n" + "\n" + "Usage: hf cryptorf dump [h] [card memory] \n" + "Options:\n" + " h this help\n" + " f filename, if no UID will be used as filename\n" + "\n" + "Examples:\n" + "\thf cryptorf dump\n" + "\thf cryptorf dump f mydump"); + return PM3_SUCCESS; +} + +static int switch_off_field_cryptorf(void) { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_DISCONNECT, 0, 0, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdHFCryptoRFList(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdTraceList("14b"); + return PM3_SUCCESS; +} + +static int CmdHFCryptoRFSim(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_cryptorf_sim(); + + uint32_t pupi = 0; + if (cmdp == 'u') { + pupi = param_get32ex(Cmd, 1, 0, 16); + } + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_SIMULATE, pupi, 0, 0, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdHF14BSniff(const char *Cmd) { + + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_cryptorf_sniff(); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); + return PM3_SUCCESS; +} + +static bool get_14b_UID(iso14b_card_select_t *card) { + + if (!card) + return false; + + int8_t retry = 3; + PacketResponseNG resp; + + // test for 14b SR + while (retry--) { + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + + uint8_t status = resp.oldarg[0]; + if (status == 0) { + memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + return true; + } + } + } // retry + + // test 14b standard + retry = 3; + while (retry--) { + + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + if (WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + + uint8_t status = resp.oldarg[0]; + if (status == 0) { + memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + return true; + } + } + } // retry + + if (retry <= 0) + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + + return false; +} + +static int CmdHFCryptoRFInfo(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_cryptorf_info(); + + bool verbose = (cmdp == 'v'); + + int res = infoHFCryptoRF(verbose); + if (res != PM3_SUCCESS && verbose) { + PrintAndLogEx(FAILED, "no 14443-B tag found"); + } + return res; +} + +static int CmdHFCryptoRFReader(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_cryptorf_reader(); + + bool verbose = (cmdp == 'v'); + + int res = readHFCryptoRF(verbose); + if (res != PM3_SUCCESS && verbose) { + PrintAndLogEx(FAILED, "no 14443-B tag found"); + } + return res; +} + +// need to write to file +static int CmdHFCryptoRFDump(const char *Cmd) { + + uint8_t fileNameLen = 0; + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + bool errors = false; + uint8_t cmdp = 0, cardtype = 1; + uint16_t cardsize = 0; + uint8_t blocks = 0; + iso14b_card_select_t card; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_cryptorf_dump(); + case 'f': + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + cmdp += 2; + break; + default: + if (cmdp == 0) { + cardtype = param_get8ex(Cmd, cmdp, 1, 10); + cmdp++; + } else { + PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + } + + //Validations + if (errors) return usage_hf_cryptorf_dump(); + + switch (cardtype) { + case 2: + cardsize = (512 / 8) + 4; + blocks = 0x0F; + break; + case 1: + default: + cardsize = (4096 / 8) + 4; + blocks = 0x7F; + break; + } + + if (!get_14b_UID(&card)) { + PrintAndLogEx(WARNING, "No tag found."); + return PM3_SUCCESS; + } + + if (fileNameLen < 1) { + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += sprintf(fptr, "hf-cryptorf-"); + FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); + } + + // detect blocksize from card :) + PrintAndLogEx(NORMAL, "Reading memory from tag UID %s", sprint_hex(card.uid, card.uidlen)); + + uint8_t data[cardsize]; + memset(data, 0, sizeof(data)); + + int blocknum = 0; + uint8_t *recv = NULL; + + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); + + //select + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (resp.oldarg[0]) { + PrintAndLogEx(INFO, "failed to select %" PRId64 " | %" PRId64, resp.oldarg[0], resp.oldarg[1]); + goto out; + } + } + + uint8_t req[2] = {ISO14443B_READ_BLK}; + + for (int retry = 0; retry < 5; retry++) { + + req[1] = blocknum; + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); + + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + + uint8_t status = resp.oldarg[0] & 0xFF; + if (status > 0) { + continue; + } + + uint16_t len = (resp.oldarg[1] & 0xFFFF); + recv = resp.data.asBytes; + + if (!check_crc(CRC_14443_B, recv, len)) { + PrintAndLogEx(FAILED, "crc fail, retrying one more time"); + continue; + } + + memcpy(data + (blocknum * 4), resp.data.asBytes, 4); + + if (blocknum == 0xFF) { + //last read. + break; + } + + + retry = 0; + blocknum++; + if (blocknum > blocks) { + // read config block + blocknum = 0xFF; + } + + printf("."); + fflush(stdout); + } + } + + if (blocknum != 0xFF) { + PrintAndLogEx(NORMAL, "\n Dump failed"); + goto out; + } + + PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, "block# | data | ascii"); + PrintAndLogEx(NORMAL, "---------+--------------+----------"); + + for (int i = 0; i <= blocks; i++) { + PrintAndLogEx(NORMAL, + "%3d/0x%02X | %s | %s", + i, + i, + sprint_hex(data + (i * 4), 4), + sprint_ascii(data + (i * 4), 4) + ); + } + + PrintAndLogEx(NORMAL, "\n"); + + + size_t datalen = (blocks + 1) * 4; + saveFileEML(filename, data, datalen, 4); + saveFile(filename, ".bin", data, datalen); +out: + return switch_off_field_cryptorf(); +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdHFCryptoRFDump, IfPm3Iso14443b, "Read all memory pages of an CryptoRF tag, save to file"}, + {"info", CmdHFCryptoRFInfo, IfPm3Iso14443b, "Tag information"}, + {"list", CmdHFCryptoRFList, AlwaysAvailable, "List ISO 14443B history"}, + {"reader", CmdHFCryptoRFReader, IfPm3Iso14443b, "Act as a CryptoRF reader to identify a tag"}, + {"sim", CmdHFCryptoRFSim, IfPm3Iso14443b, "Fake CryptoRF tag"}, + {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop CryptoRF"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHFCryptoRF(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} + +// Print extented information about tag. +int infoHFCryptoRF(bool verbose) { + + int res = PM3_ESOFT; + + // 14b get and print UID only (general info) + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + switch_off_field_cryptorf(); + return false; + } + + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 0: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); + res = PM3_SUCCESS; + break; + case 2: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); + break; + case 3: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + default: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); + break; + } + + return res; +} + +// get and print general info cryptoRF +int readHFCryptoRF(bool verbose) { + + int res = PM3_ESOFT; + + // 14b get and print UID only (general info) + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { + if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + return PM3_ETIMEOUT; + } + + iso14b_card_select_t card; + memcpy(&card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t)); + + uint64_t status = resp.oldarg[0]; + + switch (status) { + case 0: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); + res = PM3_SUCCESS; + break; + case 2: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail"); + break; + case 3: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 CRC fail"); + break; + default: + if (verbose) PrintAndLogEx(FAILED, "ISO 14443-b card select failed"); + break; + } + return res; +} diff --git a/client/cmdhfcryptorf.h b/client/cmdhfcryptorf.h new file mode 100644 index 000000000..82508e415 --- /dev/null +++ b/client/cmdhfcryptorf.h @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2020 iceman +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// High frequency CryptoRF commands (ISO14443B) +//----------------------------------------------------------------------------- + +#ifndef CMDHFCRYPTORF_H__ +#define CMDHFCRYPTORF_H__ + +#include "common.h" + +int CmdHFCryptoRF(const char *Cmd); + +int infoHFCryptoRF(bool verbose); +int readHFCryptoRF(bool verbose); +#endif From 5e9e6a9ad84e568a7c9c1063f81cb76e55306e84 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:17:05 +0200 Subject: [PATCH 07/21] prepp hookup for cryptorf cmds --- client/Makefile | 1 + client/cmdhf.c | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/client/Makefile b/client/Makefile index a09a033d9..ed2491202 100644 --- a/client/Makefile +++ b/client/Makefile @@ -205,6 +205,7 @@ CMDSRCS = crapto1/crapto1.c \ cmdhffido.c \ cmdhffelica.c \ cmdhfthinfilm.c \ + cmdhfcryptorf.c \ cmdhflto.c \ cmdhw.c \ cmdlf.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index dfc2a3d47..773ffe431 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -34,6 +34,7 @@ #include "cmdhffido.h" // FIDO authenticators #include "cmdhfthinfilm.h" // Thinfilm #include "cmdhflto.h" // LTO-CM +#include "cmdhfcryptorf.h" // CryptoRF #include "cmdtrace.h" // trace list #include "ui.h" #include "cmddata.h" @@ -149,11 +150,22 @@ int CmdHFSearch(const char *Cmd) { res = PM3_SUCCESS; } } +/* + // 14b and iclass is the longest test (put last) + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, "Searching for CryptoRF tag..."); + if (IfPm3Iso14443b()) { + if (readHFCryptoRF(false) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("CryptoRF tag") "found\n"); + res = PM3_SUCCESS; + } + } +*/ // 14b and iclass is the longest test (put last) PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ISO14443-B tag..."); - if (IfPm3Iso14443a()) { + if (IfPm3Iso14443b()) { if (readHF14B(false) == 1) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") "found\n"); res = PM3_SUCCESS; @@ -281,6 +293,7 @@ static command_t CommandTable[] = { {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, {"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"}, {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, +// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"}, {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"}, {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, From 227900efee1be6df946b722a467e840b47c88af2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:54:53 +0200 Subject: [PATCH 08/21] eload/esave skeleton for cryptorf --- client/cmdhfcryptorf.c | 173 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 8 deletions(-) diff --git a/client/cmdhfcryptorf.c b/client/cmdhfcryptorf.c index 76441596f..5767b9ed5 100644 --- a/client/cmdhfcryptorf.c +++ b/client/cmdhfcryptorf.c @@ -82,6 +82,31 @@ static int usage_hf_cryptorf_dump(void) { "\thf cryptorf dump f mydump"); return PM3_SUCCESS; } +static int usage_hf_cryptorf_eload(void) { + PrintAndLogEx(NORMAL, "It loads a binary dump into emulator memory\n" + "Usage: hf cryptorf eload [f ]\n" + "Options:\n" + " h this help\n" + " f filename, if no UID will be used as filename\n" + "\n" + "Examples:\n" + _YELLOW_(" hf cryptorf eload f filename") + ); + return PM3_SUCCESS; +} +static int usage_hf_cryptorf_esave(void) { + PrintAndLogEx(NORMAL, "It saves bin/eml/json dump file of emulator memory\n" + " Usage: hf cryptorf esave [f ]\n" + "Options:\n" + " h this help\n" + " f filename, if no UID will be used as filename\n" + "\n" + "Examples:\n" + _YELLOW_(" hf cryptorf esave ") + _YELLOW_(" hf cryptorf esave f filename") + ); + return PM3_SUCCESS; +} static int switch_off_field_cryptorf(void) { clearCommandBuffer(); @@ -109,7 +134,7 @@ static int CmdHFCryptoRFSim(const char *Cmd) { return PM3_SUCCESS; } -static int CmdHF14BSniff(const char *Cmd) { +static int CmdHFCryptoRFSniff(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_cryptorf_sniff(); @@ -342,14 +367,146 @@ out: return switch_off_field_cryptorf(); } +static int CmdHFCryptoRFELoad(const char *Cmd) { + + size_t datalen = 1024; + int fileNameLen = 0; + char filename[FILE_PATH_SIZE] = {0x00}; + bool errors = false; + uint8_t cmdp = 0; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h' : + return usage_hf_cryptorf_eload(); + case 'f' : + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (!fileNameLen) + errors = true; + if (fileNameLen > FILE_PATH_SIZE - 5) + fileNameLen = FILE_PATH_SIZE - 5; + cmdp += 2; + break; + default : + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || strlen(Cmd) == 0) return usage_hf_cryptorf_eload(); + + // set up buffer + uint8_t *data = calloc(datalen, sizeof(uint8_t)); + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + if (loadFile_safe(filename, ".bin", (void **)&data, &datalen) != PM3_SUCCESS) { + free(data); + PrintAndLogEx(WARNING, "Error, reading file"); + return PM3_EFILE; + } + + PrintAndLogEx(SUCCESS, "Uploading to emulator memory"); + +/* + // fast push mode + conn.block_after_ACK = true; + + //Send to device + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = bytes_read; + + while (bytes_remaining > 0) { + uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE, bytes_remaining); + if (bytes_in_packet == bytes_remaining) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + clearCommandBuffer(); + SendCommandOLD(CMD_HF_CRYPTORF_EML_MEMSET, bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + } + free(data); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Done"); +*/ + return PM3_SUCCESS; +} + +static int CmdHFCryptoRFESave(const char *Cmd) { + + char filename[FILE_PATH_SIZE] = {0}; + char *fptr = filename; + int fileNameLen = 0; + size_t numofbytes = 1024; + bool errors = false; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h' : + return usage_hf_cryptorf_esave(); + case 'f' : + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (!fileNameLen) + errors = true; + if (fileNameLen > FILE_PATH_SIZE - 5) + fileNameLen = FILE_PATH_SIZE - 5; + cmdp += 2; + break; + default : + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || strlen(Cmd) == 0) return usage_hf_cryptorf_esave(); + + // set up buffer + uint8_t *data = calloc(numofbytes, sizeof(uint8_t)); + if (!data) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + // download emulator memory + PrintAndLogEx(SUCCESS, "Reading emulator memory..."); + if (!GetFromDevice(BIG_BUF_EML, data, numofbytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(data); + return PM3_ETIMEOUT; + } + + // user supplied filename? + if (fileNameLen < 1) { + PrintAndLogEx(INFO, "Using UID as filename"); + fptr += sprintf(fptr, "hf-cryptorf-"); + FillFileNameByUID(fptr, data, "-dump", 4); + } + + saveFile(filename, ".bin", data, numofbytes); + //needs to change + saveFileEML(filename, data, numofbytes, 8); + //needs to change + saveFileJSON(filename, jsfRaw, data, numofbytes); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"dump", CmdHFCryptoRFDump, IfPm3Iso14443b, "Read all memory pages of an CryptoRF tag, save to file"}, - {"info", CmdHFCryptoRFInfo, IfPm3Iso14443b, "Tag information"}, - {"list", CmdHFCryptoRFList, AlwaysAvailable, "List ISO 14443B history"}, - {"reader", CmdHFCryptoRFReader, IfPm3Iso14443b, "Act as a CryptoRF reader to identify a tag"}, - {"sim", CmdHFCryptoRFSim, IfPm3Iso14443b, "Fake CryptoRF tag"}, - {"sniff", CmdHF14BSniff, IfPm3Iso14443b, "Eavesdrop CryptoRF"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdHFCryptoRFDump, IfPm3Iso14443b, "Read all memory pages of an CryptoRF tag, save to file"}, + {"info", CmdHFCryptoRFInfo, IfPm3Iso14443b, "Tag information"}, + {"list", CmdHFCryptoRFList, AlwaysAvailable, "List ISO 14443B history"}, + {"reader", CmdHFCryptoRFReader, IfPm3Iso14443b, "Act as a CryptoRF reader to identify a tag"}, + {"sim", CmdHFCryptoRFSim, IfPm3Iso14443b, "Fake CryptoRF tag"}, + {"sniff", CmdHFCryptoRFSniff, IfPm3Iso14443b, "Eavesdrop CryptoRF"}, + {"eload", CmdHFCryptoRFELoad, AlwaysAvailable, "Load binary dump to emulator memory"}, + {"esave", CmdHFCryptoRFESave, AlwaysAvailable, "Save emulator memory to binary file"}, + {NULL, NULL, NULL, NULL} }; From 961eb193d15d5d2a79d3cfe4c1306ff98d067709 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:55:12 +0200 Subject: [PATCH 09/21] text --- client/cmdhffelica.c | 62 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 84339a05c..dc3b07a1b 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -1847,37 +1847,37 @@ int readFelicaUid(bool verbose) { } static command_t CommandTable[] = { - {"----------- General -----------", CmdHelp, IfPm3Iso14443a, ""}, - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, - {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, - {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, - {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, - {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, - {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, - {"----------- FeliCa Standard -----------", CmdHelp, IfPm3Iso14443a, ""}, - //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, - {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, - {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, - {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, - {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."}, - {"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"}, - {"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"}, - //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, - //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, - //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, - //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."}, - {"rqspecver", CmdHFFelicaRequestSpecificationVersion, IfPm3Felica, "acquire the version of card OS."}, - {"resetmode", CmdHFFelicaResetMode, IfPm3Felica, "reset Mode to Mode 0."}, - //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, - //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, - //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, - //{"writev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."}, - //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."}, - {"----------- FeliCa Light -----------", CmdHelp, IfPm3Iso14443a, ""}, - {"litesim", CmdHFFelicaSimLite, IfPm3Felica, " - only reply to poll request"}, - {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, - // {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"} + {"----------- General -----------", CmdHelp, AlwaysAvailable, ""}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFFelicaList, AlwaysAvailable, "List ISO 18092/FeliCa history"}, + {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, + {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, + {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, + {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, + {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, + {"----------- FeliCa Standard -----------", CmdHelp, AlwaysAvailable, ""}, + //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, + {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, + {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, + {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, + {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."}, + {"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"}, + {"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"}, + //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, + //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, + //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, + //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."}, + {"rqspecver", CmdHFFelicaRequestSpecificationVersion, IfPm3Felica, "acquire the version of card OS."}, + {"resetmode", CmdHFFelicaResetMode, IfPm3Felica, "reset Mode to Mode 0."}, + //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, + //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, + //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, + //{"writev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to authentication-required Service."}, + //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."}, + {"----------- FeliCa Light -----------", CmdHelp, AlwaysAvailable, ""}, + {"litesim", CmdHFFelicaSimLite, IfPm3Felica, " - only reply to poll request"}, + {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, + // {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"} {NULL, NULL, NULL, NULL} }; From a32f1520db0032f5c659029472486f1079dbc0d9 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:55:51 +0200 Subject: [PATCH 10/21] chg: hf legic eload/esave - always available --- client/cmdhflegic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 8fc3ed357..f39d545f0 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -1359,8 +1359,8 @@ static command_t CommandTable[] = { {"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"}, {"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"}, {"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"}, - {"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"}, - {"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"}, + {"eload", CmdLegicELoad, AlwaysAvailable, "Load binary dump to emulator memory"}, + {"esave", CmdLegicESave, AlwaysAvailable, "Save emulator memory to binary file"}, {"wipe", CmdLegicWipe, IfPm3Legicrf, "Wipe a LEGIC Prime tag"}, {NULL, NULL, NULL, NULL} }; From e1c64d3eef42cf6de1ab846bcf13aafb7959c468 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 06:56:23 +0200 Subject: [PATCH 11/21] text --- client/cmdhfmf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 4c49187ca..e43461591 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -3712,7 +3712,7 @@ int CmdHF14AMfELoad(const char *Cmd) { } } - PrintAndLogEx(INFO, "Copying to emulator memory"); + PrintAndLogEx(INFO, "Uploading to emulator memory"); // fast push mode conn.block_after_ACK = true; From 97f06ddcfba646a59eb7b94bca15a087ea45f1cc Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 07:15:34 +0200 Subject: [PATCH 12/21] coverity fixes --- client/cmdhflegic.c | 64 +++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index f39d545f0..1e06aba8a 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -1020,37 +1020,41 @@ static int CmdLegicDump(const char *Cmd) { static int CmdLegicRestore(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0x00}; - size_t fileNlen = 0; - bool errors = false, shall_obsfuscate = false; + bool errors = false, shall_obsfuscate = false, have_filename = false; size_t numofbytes; uint8_t cmdp = 0; - memset(filename, 0, sizeof(filename)); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': + case 'h': { errors = true; break; - case 'f': - fileNlen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!fileNlen) + } + case 'f': { + int len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (!len) errors = true; + else + have_filename = true; - if (fileNlen > FILE_PATH_SIZE - 5) - fileNlen = FILE_PATH_SIZE - 5; cmdp += 2; break; - case 'x': + } + case 'x': { shall_obsfuscate = true; cmdp++; break; - default: + } + default: { PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; + } } } + if (have_filename == false) + errors = true; + //Validations if (errors || cmdp == 0) return usage_legic_restore(); @@ -1133,45 +1137,55 @@ static int CmdLegicRestore(const char *Cmd) { static int CmdLegicELoad(const char *Cmd) { size_t numofbytes = 256; - int fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0x00}; - bool errors = false, shall_obsfuscate = false; + bool errors = false, shall_obsfuscate = false, have_filename = false; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h' : + case 'h' : { return usage_legic_eload(); - case 'f' : - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!fileNameLen) + } + case 'f' : { + int len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (!len) errors = true; - if (fileNameLen > FILE_PATH_SIZE - 5) - fileNameLen = FILE_PATH_SIZE - 5; + else + have_filename = true; + cmdp += 2; break; - case 'x': + } + case 'x': { shall_obsfuscate = true; cmdp++; break; - case '0' : + } + case '0' : { numofbytes = 22; cmdp++; break; - case '1' : + } + case '1' : { numofbytes = 256; cmdp++; break; - case '2' : + } + case '2' : { numofbytes = 1024; cmdp++; break; - default : + } + default : { PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; + } } } + if (have_filename == false) + errors = true; + //Validations if (errors || strlen(Cmd) == 0) return usage_legic_eload(); From b8bbc1d0a5faa5dd6775e4c44edbcf651b106d96 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 07:29:12 +0200 Subject: [PATCH 13/21] filename checks --- client/cmdhflegic.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 1e06aba8a..c6de1379d 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -1031,12 +1031,11 @@ static int CmdLegicRestore(const char *Cmd) { break; } case 'f': { - int len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!len) - errors = true; - else - have_filename = true; - + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "Filename too long"); + break; + } + have_filename = true; cmdp += 2; break; } @@ -1147,12 +1146,11 @@ static int CmdLegicELoad(const char *Cmd) { return usage_legic_eload(); } case 'f' : { - int len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!len) - errors = true; - else - have_filename = true; - + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "Filename too long"); + break; + } + have_filename = true; cmdp += 2; break; } From 97ef641fad7227926789f96cc27463e732cd16f7 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 07:29:39 +0200 Subject: [PATCH 14/21] coverity fix, format specifier --- client/cmdhficlass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 72a7eaad2..c3042d874 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -2050,7 +2050,7 @@ static int CmdHFiClassReadTagFile(const char *Cmd) { if (verbose) { PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); - PrintAndLogEx(INFO, "File size %d bytes, file blocks %d (0x%02x)", bytes_read, bytes_read >> 3, bytes_read >> 3); + PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3)); PrintAndLogEx(INFO, "Printing blocks from"); PrintAndLogEx(INFO, "start " _YELLOW_("0x%02x") "end " _YELLOW_("0x%02x"), (startblock == 0) ? 6 : startblock, endblock); } From fcf7bd24a651cafffd21a0e4b9a1d01a6f49a12e Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 08:02:48 +0200 Subject: [PATCH 15/21] fix coverity 278907, 278906 --- client/cmdhfcryptorf.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/client/cmdhfcryptorf.c b/client/cmdhfcryptorf.c index 5767b9ed5..1dd555b80 100644 --- a/client/cmdhfcryptorf.c +++ b/client/cmdhfcryptorf.c @@ -372,7 +372,7 @@ static int CmdHFCryptoRFELoad(const char *Cmd) { size_t datalen = 1024; int fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0x00}; - bool errors = false; + bool errors = false, has_filename = false; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -380,11 +380,12 @@ static int CmdHFCryptoRFELoad(const char *Cmd) { case 'h' : return usage_hf_cryptorf_eload(); case 'f' : - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (!fileNameLen) + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "Filename too long"); errors = true; - if (fileNameLen > FILE_PATH_SIZE - 5) - fileNameLen = FILE_PATH_SIZE - 5; + break; + } + has_filename = true; cmdp += 2; break; default : @@ -393,6 +394,9 @@ static int CmdHFCryptoRFELoad(const char *Cmd) { break; } } + if (has_filename == false) + errors = true; + //Validations if (errors || strlen(Cmd) == 0) return usage_hf_cryptorf_eload(); @@ -430,11 +434,11 @@ static int CmdHFCryptoRFELoad(const char *Cmd) { bytes_remaining -= bytes_in_packet; bytes_sent += bytes_in_packet; } +*/ free(data); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Done"); -*/ - return PM3_SUCCESS; + return PM3_SUCCESS; } static int CmdHFCryptoRFESave(const char *Cmd) { From f461a4e5fb197bea71f844f78f8cf02785d65b32 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 08:03:30 +0200 Subject: [PATCH 16/21] fix coverity 278907, 278906 --- client/cmdhfcryptorf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/cmdhfcryptorf.c b/client/cmdhfcryptorf.c index 1dd555b80..c6d43ff46 100644 --- a/client/cmdhfcryptorf.c +++ b/client/cmdhfcryptorf.c @@ -370,7 +370,6 @@ out: static int CmdHFCryptoRFELoad(const char *Cmd) { size_t datalen = 1024; - int fileNameLen = 0; char filename[FILE_PATH_SIZE] = {0x00}; bool errors = false, has_filename = false; uint8_t cmdp = 0; From 7b14fd7212b2e5f053b1f00dbc4b35d953c84f40 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 6 Apr 2020 16:20:57 +1000 Subject: [PATCH 17/21] Code Clean --- client/emv/emvjson.c | 1 + client/fileutils.c | 9 ++++----- client/proxmark3.c | 7 +++---- client/settings.c | 14 ++++++-------- client/settings.h | 14 ++++++++++---- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c index 9b86b38ca..968b51d51 100644 --- a/client/emv/emvjson.c +++ b/client/emv/emvjson.c @@ -97,6 +97,7 @@ int JsonSaveStr(json_t *root, const char *path, const char *value) { int JsonSaveBoolean(json_t *root, const char *path, bool value) { return JsonSaveJsonObject(root, path, json_boolean(value)); } + int JsonSaveBufAsHexCompact(json_t *elm, const char *path, uint8_t *data, size_t datalen) { char *msg = sprint_hex_inrow(data, datalen); if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ') diff --git a/client/fileutils.c b/client/fileutils.c index 5ce1f3a6a..50d3ca9d6 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -38,6 +38,8 @@ // this define is needed for scandir/alphasort to work #define _GNU_SOURCE #include "fileutils.h" +#include "settings.h" + #include #include @@ -52,9 +54,6 @@ #define PATH_MAX_LENGTH 200 -extern void JsonLoadSettingsCallback (json_t *root); -extern void JsonSaveSettingsCallback (json_t *root); - struct wave_info_t { char signature[4]; uint32_t filesize; @@ -429,7 +428,7 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } break; case jsfSettings: - JsonSaveSettingsCallback (root); + settings_save_callback (root); break; default: break; @@ -870,7 +869,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ *datalen = sptr; } if (!strcmp(ctype,"settings")) { - JsonLoadSettingsCallback (root); + settings_load_callback (root); } PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), fileName); out: diff --git a/client/proxmark3.c b/client/proxmark3.c index 504ae93e5..168b5b960 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -558,7 +558,6 @@ int main(int argc, char *argv[]) { /* initialize history */ using_history(); - #ifdef RL_STATE_READCMD rl_extend_line_buffer(1024); @@ -583,9 +582,9 @@ int main(int argc, char *argv[]) { set_my_executable_path(); set_my_user_directory(); - // Settings - settingsLoad (); - settingsSave (); + // Settings Load and Test + settings_load (); + settings_save (); printf ("Ver : %s\n",mySettings.version); // End Settings diff --git a/client/settings.c b/client/settings.c index a3571c566..976121eed 100644 --- a/client/settings.c +++ b/client/settings.c @@ -43,10 +43,8 @@ #include "comms.h" #include "emv/emvjson.h" -// settings_t mySettings; - // Load all settings into memory (struct) -void settingsLoad (void) +int settings_load (void) { // loadFileJson wants these, so pass in place holder values, though not used // in settings load; @@ -79,17 +77,17 @@ void settingsLoad (void) printf (" window_hsize (int) : [%d]\n",mySettings.window_hsize); printf (" window_wsize (int) : [%d]\n",mySettings.window_wsize); + return PM3_SUCCESS; } // Save all settings from memory (struct) to file -int settingsSave (void) +int settings_save (void) { // Note sure if backup has value ? char backupFilename[500]; - // if (mySettings.loaded) snprintf (backupFilename,sizeof(backupFilename),"%s.bak",settingsFilename); - + if (fileExists (backupFilename)) { if (remove (backupFilename) != 0) { PrintAndLogEx (FAILED, "Error - could not delete old settings backup file \"%s\"",backupFilename); @@ -115,7 +113,7 @@ int settingsSave (void) return PM3_SUCCESS; } -void JsonSaveSettingsCallback (json_t *root) +void settings_save_callback (json_t *root) { // extern settings_t mySettings; @@ -141,7 +139,7 @@ void JsonSaveSettingsCallback (json_t *root) JsonSaveInt (root,"window.wsize",mySettings.window_wsize); } -void JsonLoadSettingsCallback (json_t *root) +void settings_load_callback (json_t *root) { // extern settings_t mySettings; json_error_t up_error = {0}; diff --git a/client/settings.h b/client/settings.h index f0093c207..799af7caa 100644 --- a/client/settings.h +++ b/client/settings.h @@ -8,10 +8,13 @@ //----------------------------------------------------------------------------- // Settings Functions //----------------------------------------------------------------------------- +#ifndef settings_h +#define settings_h #include "fileutils.h" #define settingsFilename "settings.json" + typedef struct { bool loaded; char version[20]; @@ -23,10 +26,13 @@ typedef struct { int window_wsize; } settings_t; +// Settings struct so as to be available to other modules by including settings.h settings_t mySettings; -void settingsLoad (void); -int settingsSave (void); +int settings_load (void); +int settings_save (void); -void JsonSaveCallback ( json_t *root); -void JsonLoadCallback ( json_t *root); +void settings_save_callback (json_t *root); +void settings_load_callback (json_t *root); + +#endif From f0b0d10ee1a67ae6de2e3d937ba3b85eee656f14 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 6 Apr 2020 16:36:12 +1000 Subject: [PATCH 18/21] Comment out test calls --- client/fileutils.c | 1 - client/proxmark3.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/fileutils.c b/client/fileutils.c index 50d3ca9d6..05a7e8949 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -40,7 +40,6 @@ #include "fileutils.h" #include "settings.h" - #include #include diff --git a/client/proxmark3.c b/client/proxmark3.c index 168b5b960..0438f81ad 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -583,9 +583,9 @@ int main(int argc, char *argv[]) { set_my_user_directory(); // Settings Load and Test - settings_load (); - settings_save (); - printf ("Ver : %s\n",mySettings.version); + // settings_load (); + // settings_save (); + // printf ("Ver : %s\n",mySettings.version); // End Settings for (int i = 1; i < argc; i++) { From 173583a5483535cacd5f8ba95c0f514d56724092 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 09:46:22 +0200 Subject: [PATCH 19/21] fix coverity 278900 --- client/cmdhfmfu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 7c204f861..fd3ad5aeb 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -2808,6 +2808,7 @@ static int CmdHF14MfuNDEF(const char *Cmd) { if (status == -1) { DropField(); PrintAndLogEx(ERR, "Error: tag didn't answer to READ"); + free(records); return PM3_ESOFT; } } From b6e85c865d2cf1b0bb55c8f53bc8b5afa0e76357 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 10:54:58 +0200 Subject: [PATCH 20/21] more settings emoji, hints. --- client/settings.c | 68 +++++++++++++++++++++++++++-------------------- client/settings.h | 2 ++ 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/client/settings.c b/client/settings.c index 976121eed..79fa00fd1 100644 --- a/client/settings.c +++ b/client/settings.c @@ -44,8 +44,7 @@ #include "emv/emvjson.h" // Load all settings into memory (struct) -int settings_load (void) -{ +int settings_load (void) { // loadFileJson wants these, so pass in place holder values, though not used // in settings load; uint8_t dummyData = 0x00; @@ -68,25 +67,27 @@ int settings_load (void) int window_ypos; int window_hsize; int window_wsize; + bool use_emojis + bool use_hints */ - printf (" Settings Version : [%s]\n",mySettings.version); - printf (" os_windows_usecolor (bool) : [%d]\n",mySettings.os_windows_usecolor); - printf (" os_windows_useAnsicolor (bool) : [%d]\n",mySettings.os_windows_useansicolor); - printf (" window_xpos (int) : [%d]\n",mySettings.window_xpos); - printf (" window_ypos (int) : [%d]\n",mySettings.window_ypos); - printf (" window_hsize (int) : [%d]\n",mySettings.window_hsize); - printf (" window_wsize (int) : [%d]\n",mySettings.window_wsize); - + printf (" Settings Version : [%s]\n", mySettings.version); + printf (" os_windows_usecolor (bool) : [%d]\n", mySettings.os_windows_usecolor); + printf (" os_windows_useAnsicolor (bool) : [%d]\n", mySettings.os_windows_useansicolor); + printf (" window_xpos (int) : [%d]\n", mySettings.window_xpos); + printf (" window_ypos (int) : [%d]\n", mySettings.window_ypos); + printf (" window_hsize (int) : [%d]\n", mySettings.window_hsize); + printf (" window_wsize (int) : [%d]\n", mySettings.window_wsize); + printf (" use emoji (bool) : [%d]\n", mySettings.use_emojis); + printf (" use hints (bool) : [%d]\n", mySettings.use_hints); return PM3_SUCCESS; } // Save all settings from memory (struct) to file -int settings_save (void) -{ +int settings_save(void) { // Note sure if backup has value ? char backupFilename[500]; - snprintf (backupFilename,sizeof(backupFilename),"%s.bak",settingsFilename); + snprintf(backupFilename, sizeof(backupFilename),"%s.bak",settingsFilename); if (fileExists (backupFilename)) { if (remove (backupFilename) != 0) { @@ -105,18 +106,14 @@ int settings_save (void) uint8_t dummyData = 0x00; size_t dummyDL = 0x00; - // int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen); - if (saveFileJSON(settingsFilename, jsfSettings, &dummyData, dummyDL) == PM3_SUCCESS) PrintAndLogEx (NORMAL, "settings have been saved to \"%s\"",settingsFilename); return PM3_SUCCESS; } -void settings_save_callback (json_t *root) -{ - // extern settings_t mySettings; - +void settings_save_callback(json_t *root) { + printf ("==> Save Settings\n"); //JsonSaveStr(root, "FileType", "settings"); //JsonSaveStr (root,"Test1.Test2","test settings"); @@ -131,23 +128,24 @@ void settings_save_callback (json_t *root) */ JsonSaveStr (root,"FileType","settings"); JsonSaveStr (root,"version","1.0 Nov 2019");//mySettings.version); - JsonSaveBoolean (root,"os.windows.useColor",mySettings.os_windows_usecolor); - JsonSaveBoolean (root,"os.windows.useAnsiColor",mySettings.os_windows_useansicolor); - JsonSaveInt (root,"window.xpos",mySettings.window_xpos); - JsonSaveInt (root,"window.ypos",mySettings.window_ypos); - JsonSaveInt (root,"window.hsize",mySettings.window_hsize); - JsonSaveInt (root,"window.wsize",mySettings.window_wsize); + JsonSaveBoolean (root,"os.windows.useColor", mySettings.os_windows_usecolor); + JsonSaveBoolean (root,"os.windows.useAnsiColor", mySettings.os_windows_useansicolor); + JsonSaveInt (root,"window.xpos", mySettings.window_xpos); + JsonSaveInt (root,"window.ypos", mySettings.window_ypos); + JsonSaveInt (root,"window.hsize", mySettings.window_hsize); + JsonSaveInt (root,"window.wsize", mySettings.window_wsize); + JsonSaveBoolean (root,"client.useEmojis", mySettings.use_emojis); + JsonSaveBoolean (root,"client.useHints", mySettings.use_hints); } -void settings_load_callback (json_t *root) -{ -// extern settings_t mySettings; +void settings_load_callback(json_t *root) { + json_error_t up_error = {0}; int b1; int i1; const char *s1; - if (json_unpack_ex(root, &up_error , 0, "{s:s}","version",&s1) == 0) + if (json_unpack_ex(root, &up_error , 0, "{s:s}","version", &s1) == 0) strncpy (mySettings.version,s1,sizeof (mySettings.version) - 1); else strncpy (mySettings.version,"unknown",sizeof (mySettings.version) - 1); @@ -180,5 +178,17 @@ void settings_load_callback (json_t *root) mySettings.window_wsize = i1; else // default mySettings.window_wsize = 0; + + // Use EMOJIS + if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useEmojis",&b1) == 0) + mySettings.use_emojis = b1; + else // default + mySettings.use_emojis = false; + + // Use Hints + if (json_unpack_ex(root,&up_error, 0, "{s:b}","client.useHints",&b1) == 0) + mySettings.use_hints = b1; + else // default + mySettings.use_hints = false; } diff --git a/client/settings.h b/client/settings.h index 799af7caa..4bf8b2a5e 100644 --- a/client/settings.h +++ b/client/settings.h @@ -24,6 +24,8 @@ typedef struct { int window_ypos; int window_hsize; int window_wsize; + bool use_emojis; + bool use_hints; } settings_t; // Settings struct so as to be available to other modules by including settings.h From 95b48f25ef19a4e1aec0878ae896e41f77451bee Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 6 Apr 2020 10:55:18 +0200 Subject: [PATCH 21/21] coverity fix --- armsrc/lfops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 65f9e8422..a5104d98e 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2040,7 +2040,7 @@ void T55xx_ChkPwds(uint8_t flags) { if (isok != sizeof(counter)) goto OUT; - pwdCount = counter[1] << 8 | counter[0]; + pwdCount = (uint16_t)(counter[1] << 8 | counter[0]); if (pwdCount == 0 || pwdCount == 0xFFFF) goto OUT;