diff --git a/.gitignore b/.gitignore index 349ef5efb..1b352bcfe 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ .profile *.log *.eml +*.html *.o *.a *.d diff --git a/CHANGELOG.md b/CHANGELOG.md index af8b073ca..8896f223c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Change - hint texts added to all lf clone commands (@iceman1001) + - Change `lf keri demod` - adjusted the internal id. (@mwalker33) + - Added seamless integration with cryptohelper (@iceman1001) + - Change `lf hid brute` - new params for direction (UP/DOWN); textual and main loop actually exit. (@capnkrunchy and @iceman1001) + - Fix `lf hid brute` - made it work again (@capnkrunchy) + - Fix standalone mode HF_MATTYRUN - correct logic when all keys found in printing. partial fix (@iceman1001) + - Change static nonce detection got tighter (@iceman1001) + - Improved termux notes (@msoose) + - Fix `hf mf autopwn` - works on debian 10 *nix. Bad exit commands in hardnested (@iceman1001) + - Fix `hf mf hardnested` - bad mutex strategies (@msoose) + - Change `lf hitag` - now obeys `lf config` (@iceman1001) - Ported all python 2 scripts to python 3 (@doegox and @sigwinch28) - Removed undefined exit behaviour from `analyzesize` tool: it now exits with code 2 when called with wrong args (@sigwinch28) - Replaced shebangs in scripts with more portable versions which use `/usr/bin/env` (@sigwinch28) diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index 3e53fffe9..60619e657 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -323,7 +323,7 @@ void RunMod() { Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt); int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64); if (key == -1) { - LED(LED_RED, 50); //red + LED(LED_RED, 50); Dbprintf("\t✕ Key not found for this sector!"); allKeysFound = false; // break; @@ -348,21 +348,24 @@ void RunMod() { TODO: - Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman) */ - if (!allKeysFound && keyFound) { - Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); - LED_C_ON(); //red - LED_A_ON(); //yellow - // no room to run nested attack on device (iceman) - // Do nested attack, set allKeysFound = true; - // allKeysFound = true; + if (allKeysFound) { + Dbprintf("\t✓ All keys found"); } else { - Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); - LED_C_ON(); //red + if (keyFound) { + Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); + LED_C_ON(); //red + LED_A_ON(); //yellow + // no room to run nested attack on device (iceman) + // Do nested attack, set allKeysFound = true; + // allKeysFound = true; + } else { + Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); + LED_C_ON(); //red + } } - /* - If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. - */ + // If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. + if ((transferToEml) && (allKeysFound)) { emlClearMem(); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 37c716efb..87d6bf221 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -94,7 +94,7 @@ uint8_t nonce[4]; bool key_no; static uint64_t cipher_state; -size_t blocknr; +int16_t blocknr; size_t flipped_bit = 0; uint32_t byte_value = 0; @@ -582,7 +582,7 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t Dbhexdump(4, logdata_1, false); bSuccessful = true; return false; - +/* // read next page of card until done tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE tx[1] = blocknr << 4; @@ -590,6 +590,7 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t tx[1] |= crc >> 4; tx[2] = crc << 4; *txlen = 20; +*/ } } break; @@ -1288,10 +1289,10 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { uint8_t *tx = txbuf; size_t txlen = 0; - int t_wait_1; + int t_wait_1 = 204; int t_wait_1_guard = 8; - int t_wait_2; - size_t tag_size; + int t_wait_2 = 128; + size_t tag_size = 48; bool bStop = false; // Raw demodulation/decoding by sampling edge periods @@ -1417,9 +1418,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { t_wait_2 = HITAG_T_WAIT_2_MIN; tag_size = 48; DBG DbpString("Configured for hitag2 reader"); - } else { - DBG Dbprintf("Error, unknown hitag reader type: %d", htf); - return; } // init as reader @@ -1665,10 +1663,12 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t *tx = txbuf; size_t txlen = 0; - int t_wait_1; + + int t_wait_1 = 204; int t_wait_1_guard = 8; - int t_wait_2; - size_t tag_size; + int t_wait_2 = 128; + size_t tag_size = 48; + bool bStop = false; // Raw demodulation/decoding by sampling edge periods @@ -1743,9 +1743,6 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { t_wait_2 = HITAG_T_WAIT_2_MIN; tag_size = 48; DbpString("Configured for hitag2 writer"); - } else { - DBG Dbprintf("Error, unknown hitag writer type: %d", htf); - return; } uint8_t tag_modulation; diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index 63b246025..32d1e73b6 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -133,16 +133,18 @@ size_t lf_detect_gap(size_t max) { } void lf_reset_counter() { + // TODO: find out the correct reset settings for tag and reader mode - if (reader_mode) { +// if (reader_mode) { // Reset values for reader mode rising_edge = false; previous_adc_val = 0xFF; - } else { + +// } else { // Reset values for tag/transponder mode - rising_edge = false; - previous_adc_val = 0xFF; - } +// rising_edge = false; +// previous_adc_val = 0xFF; +// } } bool lf_get_tag_modulation() { diff --git a/client/Makefile b/client/Makefile index 6e2ebd001..fae411a52 100644 --- a/client/Makefile +++ b/client/Makefile @@ -130,7 +130,7 @@ CORESRCS = uart_posix.c \ util_posix.c \ scandir.c \ crc16.c \ - comms.c + comms.c CMDSRCS = crapto1/crapto1.c \ crapto1/crypto1.c \ @@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \ bucketsort.c \ flash.c \ wiegand_formats.c \ - wiegand_formatutils.c + wiegand_formatutils.c \ + cardhelper.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 567600d15..d69efd475 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,8 +1,8 @@ //----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende +// 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 @@ -12,14 +12,11 @@ //----------------------------------------------------------------------------- #include "cmdhficlass.h" - #include - #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" #include "util_posix.h" - #include "comms.h" #include "mbedtls/des.h" #include "loclass/cipherutils.h" @@ -28,12 +25,14 @@ #include "loclass/elite_crack.h" #include "fileutils.h" #include "protocols.h" +#include "cardhelper.h" #include "wiegand_formats.h" #include "wiegand_formatutils.h" #define NUM_CSNS 9 #define ICLASS_KEYS_MAX 8 #define ICLASS_AUTH_RETRY 10 +#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" static int CmdHelp(const char *Cmd); @@ -290,16 +289,6 @@ static int usage_hf_iclass_permutekey(void) { return PM3_SUCCESS; } -/* -static int xorbits_8(uint8_t val) { - uint8_t res = val ^ (val >> 1); //1st pass - res = res ^ (res >> 1); // 2nd pass - res = res ^ (res >> 2); // 3rd pass - res = res ^ (res >> 4); // 4th pass - return res & 1; -} -*/ - // iclass / picopass chip config structures and shared routines typedef struct { uint8_t app_limit; //[8] @@ -311,7 +300,6 @@ typedef struct { uint8_t fuses; //[15] } picopass_conf_block; - typedef struct { uint8_t csn[8]; picopass_conf_block conf; @@ -321,6 +309,13 @@ typedef struct { uint8_t app_issuer_area[8]; } picopass_hdr; +typedef enum { + None = 0, + DES, + RFU, + TRIPLEDES +} BLOCK79ENCRYPTION; + static uint8_t isset(uint8_t val, uint8_t mask) { return (val & mask); } @@ -429,18 +424,18 @@ static void mem_app_config(const picopass_hdr *hdr) { PrintAndLogEx(NORMAL, " Credit - Kc"); } } + static void print_picopass_info(const picopass_hdr *hdr) { fuse_config(hdr); mem_app_config(hdr); } + static void printIclassDumpInfo(uint8_t *iclass_dump) { print_picopass_info((picopass_hdr *) iclass_dump); } - static int CmdHFiClassList(const char *Cmd) { (void)Cmd; // Cmd is not used so far - //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list iclass' instead"); CmdTraceList("iclass"); return PM3_SUCCESS; } @@ -475,24 +470,9 @@ static int CmdHFiClassSim(const char *Cmd) { return usage_hf_iclass_sim(); } - /* - // pre-defined 8 CSN by Holiman - uint8_t csns[8*NUM_CSNS] = { - 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x13, 0x94, 0x7E, 0x76, 0xFF, 0x12, 0xE0, - 0x2A, 0x99, 0xAC, 0x79, 0xEC, 0xFF, 0x12, 0xE0, - 0x17, 0x12, 0x01, 0xFD, 0xF7, 0xFF, 0x12, 0xE0, - 0xCD, 0x56, 0x01, 0x7C, 0x6F, 0xFF, 0x12, 0xE0, - 0x4B, 0x5E, 0x0B, 0x72, 0xEF, 0xFF, 0x12, 0xE0, - 0x00, 0x73, 0xD8, 0x75, 0x58, 0xFF, 0x12, 0xE0, - 0x0C, 0x90, 0x32, 0xF3, 0x5D, 0xFF, 0x12, 0xE0 - }; - */ - /* - pre-defined 9 CSN by iceman - only one csn depend on several others. - six depends only on the first csn, (0,1, 0x45) - */ + // remember to change the define NUM_CSNS to match. + + // pre-defined 9 CSN by iceman uint8_t csns[8 * NUM_CSNS] = { 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, @@ -505,27 +485,6 @@ static int CmdHFiClassSim(const char *Cmd) { 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 }; - /* - // pre-defined 15 CSN by Carl55 - // remember to change the define NUM_CSNS to match. - uint8_t csns[8*NUM_CSNS] = { - 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 - }; - */ /* DUMPFILE FORMAT: * @@ -801,8 +760,6 @@ static int CmdHFiClassELoad(const char *Cmd) { return PM3_SUCCESS; } -#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" - static int CmdHFiClassDecrypt(const char *Cmd) { bool errors = false; @@ -812,6 +769,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint8_t cmdp = 0; uint8_t enc_data[8] = {0}; + uint8_t dec_data[8] = {0}; size_t keylen = 0; uint8_t key[32] = {0}; @@ -865,11 +823,14 @@ static int CmdHFiClassDecrypt(const char *Cmd) { if (errors || cmdp < 1) return usage_hf_iclass_decrypt(); - if (have_key == false) { - int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); - if (res != PM3_SUCCESS) - return PM3_EINVARG; + bool use_sc = IsCryptoHelperPresent(); + if (have_key == false && use_sc == false) { + int res = loadFile_safe(ICLASS_DECRYPTION_BIN, "", (void **)&keyptr, &keylen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(INFO, "Couldn't find any decryption methods"); + return PM3_EINVARG; + } memcpy(key, keyptr, sizeof(key)); free(keyptr); } @@ -878,10 +839,13 @@ static int CmdHFiClassDecrypt(const char *Cmd) { mbedtls_des3_context ctx; mbedtls_des3_set2key_dec(&ctx, key); - uint8_t dec_data[8] = {0}; - if (have_data) { - mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); + + if (use_sc) { + Decrypt(enc_data, dec_data); + } else { + mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data); + } PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(dec_data, sizeof(dec_data))); } @@ -897,6 +861,8 @@ static int CmdHFiClassDecrypt(const char *Cmd) { getMemConfig(mem, chip, &max_blk, &app_areas, &kb); uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03); for (uint16_t blocknum = 0; blocknum < applimit; ++blocknum) { @@ -904,8 +870,17 @@ static int CmdHFiClassDecrypt(const char *Cmd) { memcpy(enc_data, decrypted + idx, 8); // block 7 or higher, and not empty 0xFF - if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) { - mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx); + // look inside block 6 to determine if aa1 is encrypted. + if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) { + + if (aa1_encryption == RFU || aa1_encryption == None) + continue; + + if (use_sc) { + Decrypt(enc_data, decrypted + idx); + } else { + mbedtls_des3_crypt_ecb(&ctx, enc_data, decrypted + idx); + } } } @@ -920,16 +895,43 @@ static int CmdHFiClassDecrypt(const char *Cmd) { printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); - uint32_t top = 0, mid, bot; - mid = bytes_to_num(decrypted + (8*7), 4); - bot = bytes_to_num(decrypted + (8*7) + 4, 4); - PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, "block 7 - Wiegand decode"); - wiegand_message_t packed = initialize_message_object(top, mid, bot); - HIDTryUnpack(&packed, true); - PrintAndLogEx(INFO, "-----------------------------------------------------------------"); - + // decode block 6 + if (memcmp(decrypted + (8*6), empty, 8) != 0 ) { + if (use_sc) { + DecodeBlock6(decrypted + (8*6)); + } + } + + // decode block 7-8-9 + if (memcmp(decrypted + (8*7), empty, 8) != 0 ) { + + //todo: remove preamble/sentinal + + uint32_t top = 0, mid, bot; + mid = bytes_to_num(decrypted + (8*7), 4); + bot = bytes_to_num(decrypted + (8*7) + 4, 4); + + PrintAndLogEx(INFO, "Block 7 binary"); + + char hexstr[8+1] = {0}; + hex_to_buffer((uint8_t *)hexstr, decrypted + (8*7), 8, sizeof(hexstr) - 1, 0, 0, true); + + char binstr[8*8+1] = {0}; + hextobinstring(binstr, hexstr); + uint8_t i=0; + while (iblockdata, sizeof(result->blockdata))); + + if (blockno == 6) { + if (IsCryptoHelperPresent()) { + DecodeBlock6(result->blockdata); + } + } + return PM3_SUCCESS; } diff --git a/client/cmdlf.c b/client/cmdlf.c index b83ed0c89..f153ba1c3 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -1339,10 +1339,10 @@ static command_t CommandTable[] = { {"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"}, {"jablotron", CmdLFJablotron, AlwaysAvailable, "{ Jablotron RFIDs... }"}, {"keri", CmdLFKeri, AlwaysAvailable, "{ KERI RFIDs... }"}, + {"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"}, {"nedap", CmdLFNedap, AlwaysAvailable, "{ Nedap RFIDs... }"}, {"nexwatch", CmdLFNEXWATCH, AlwaysAvailable, "{ NexWatch RFIDs... }"}, {"noralsy", CmdLFNoralsy, AlwaysAvailable, "{ Noralsy RFIDs... }"}, - {"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"}, {"pac", CmdLFPac, AlwaysAvailable, "{ PAC/Stanley RFIDs... }"}, {"paradox", CmdLFParadox, AlwaysAvailable, "{ Paradox RFIDs... }"}, {"pcf7931", CmdLFPCF7931, AlwaysAvailable, "{ PCF7931 CHIPs... }"}, diff --git a/client/cmdlfawid.c b/client/cmdlfawid.c index 38c3675d1..9bcf9e874 100644 --- a/client/cmdlfawid.c +++ b/client/cmdlfawid.c @@ -422,7 +422,10 @@ static int CmdAWIDClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf awid read`") "to verify"); + return res; } static int CmdAWIDBrute(const char *Cmd) { diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index a8d7e06e3..9b7fe51de 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -700,6 +700,8 @@ static int CmdEM410xWrite(const char *Cmd) { } SendCommandMIX(CMD_LF_EM410X_WRITE, card, (uint32_t)(id >> 32), (uint32_t)id, NULL, 0); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 410x_read`") "to verify"); return PM3_SUCCESS; } @@ -1037,6 +1039,9 @@ static int CmdEM4x50Write(const char *Cmd) { uint8_t ctmp = tolower(param_getchar(Cmd, 0)); if (ctmp == 'h') return usage_lf_em4x50_write(); PrintAndLogEx(NORMAL, "no implemented yet"); +// +// PrintAndLogEx(SUCCESS, "Done"); +// PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify"); return PM3_SUCCESS; } @@ -1434,9 +1439,10 @@ static int CmdEM4x05Write(const char *Cmd) { uint32_t dummy = 0; int status = demodEM4x05resp(&dummy); if (status == PM3_SUCCESS) - PrintAndLogEx(NORMAL, "Write " _GREEN_("Verified")); - else - PrintAndLogEx(NORMAL, "Write could " _RED_("not") "be verified"); + PrintAndLogEx(SUCCESS, "Success writing to tag"); + + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify"); return status; } static int CmdEM4x05Wipe(const char *Cmd) { diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 2f3f81d1d..11ec2dd64 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -301,7 +301,10 @@ static int CmdFdxClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf fdx read`") "to verify"); + return res; } static int CmdFdxSim(const char *Cmd) { diff --git a/client/cmdlfgallagher.c b/client/cmdlfgallagher.c index ef28f1326..e44682e2b 100644 --- a/client/cmdlfgallagher.c +++ b/client/cmdlfgallagher.c @@ -178,7 +178,10 @@ static int CmdGallagherClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Gallagher to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf gallagher read`") "to verify"); + return res; } static int CmdGallagherSim(const char *Cmd) { diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 201dcef84..dbe027dc3 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -83,16 +83,18 @@ static int usage_lf_hid_brute(void) { PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step"); PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w [ (decimal)>] {...}"); + PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w [ (decimal)>] [up|down] {...}"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " w : see `wiegand list` for available formats"); + PrintAndLogEx(NORMAL, " w : see " _YELLOW_("`wiegand list`") "for available formats"); PrintAndLogEx(NORMAL, " f : facility code"); PrintAndLogEx(NORMAL, " c : card number to start with"); PrintAndLogEx(NORMAL, " i : issue level"); PrintAndLogEx(NORMAL, " o : OEM code"); PrintAndLogEx(NORMAL, " d : delay betweens attempts in ms. Default 1000ms"); PrintAndLogEx(NORMAL, " v : verbose logging, show all tries"); + PrintAndLogEx(NORMAL, " up : direction to increment card number. (default is both directions)"); + PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224"); @@ -343,7 +345,8 @@ static int CmdHIDClone(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid)); - PrintAndLogEx(INFO, "Clone command sent. Try "_YELLOW_("'lf hid read'") " to verify"); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf hid read`") "to verify"); return PM3_SUCCESS; } @@ -365,14 +368,31 @@ static int CmdHIDClone(const char *Cmd) { static int CmdHIDBrute(const char *Cmd) { bool errors = false, verbose = false; - uint32_t delay = 1000; + uint32_t delay = 1000; uint8_t cmdp = 0; int format_idx = -1; + int direction = 0; char format[16] = {0}; - wiegand_card_t data; - memset(&data, 0, sizeof(wiegand_card_t)); + + wiegand_card_t cn_hi, cn_low; + memset(&cn_hi, 0, sizeof(wiegand_card_t)); while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + + char s[10] = {0}; + if (param_getstr(Cmd, cmdp, s, sizeof(s)) > 0) { + if (strlen(s) > 1) { + str_lower((char *)s); + if (str_startswith(s, "up")) { + direction = 1; + } else if (str_startswith(s, "do")) { + direction = 2; + } + cmdp++; + continue; + } + } + switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_hid_brute(); @@ -386,7 +406,7 @@ static int CmdHIDBrute(const char *Cmd) { cmdp += 2; break; case 'c': - data.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10); + cn_hi.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; case 'd': @@ -395,15 +415,15 @@ static int CmdHIDBrute(const char *Cmd) { cmdp += 2; break; case 'f': - data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10); + cn_hi.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; case 'i': - data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10); + cn_hi.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; case 'o': - data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10); + cn_hi.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; case 'v': @@ -416,13 +436,45 @@ static int CmdHIDBrute(const char *Cmd) { break; } } + + if (format_idx == -1) { + PrintAndLogEx(ERR, "You must select a wiegand format. See " _YELLOW_("`wiegand list`") "for available formats\n"); + errors = true; + } + if (errors) return usage_lf_hid_brute(); + if (verbose) { + PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx); + PrintAndLogEx(INFO, "OEM#............. %u", cn_hi.OEM); + PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel); + PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode); + PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber); + switch( direction) { + case 0: + PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH")); + break; + case 1: + PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("UP")); + break; + case 2: + PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN")); + break; + default: break; + } + } PrintAndLogEx(INFO, "Brute-forcing HID reader"); - PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command"); + PrintAndLogEx(INFO, "Press pm3-button to abort simulation or press `enter` to exit"); + + // copy values to low. + cn_low = cn_hi; // main loop - for (;;) { + // iceman: could add options for bruteforcing OEM, ISSUE or FC aswell.. + bool exitloop = false; + bool fin_hi, fin_low; + fin_hi = fin_low = false; + do { if (!session.pm3_present) { PrintAndLogEx(WARNING, "Device offline\n"); @@ -434,18 +486,44 @@ static int CmdHIDBrute(const char *Cmd) { return sendPing(); } - // Do one up - if (data.CardNumber < 0xFFFF) { - data.CardNumber++; - if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + // do one up + if (direction != 2) { + if (cn_hi.CardNumber < 0xFFFF) { + cn_hi.CardNumber++; + if (sendTry(format_idx, &cn_hi, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + } else { + fin_hi = true; + } + } + + // do one down + if (direction != 1) { + if (cn_low.CardNumber > 0) { + cn_low.CardNumber--; + if (sendTry(format_idx, &cn_low, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + } else { + fin_low = true; + } } - // Do one down (if cardnumber is given) - if (data.CardNumber > 1) { - data.CardNumber--; - if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT; + switch (direction) { + case 0: + if (fin_hi && fin_low) { + exitloop = true; + } + break; + case 1: + exitloop = fin_hi; + break; + case 2: + exitloop = fin_low; + break; + default: break; } - } + + } while (exitloop == false); + + PrintAndLogEx(INFO, "Brute forcing finished"); return PM3_SUCCESS; } diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index 9aa98524c..01eb4b8f8 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -620,7 +620,10 @@ static int CmdIndalaClone(const char *Cmd) { } print_blocks(blocks, max); - return clone_t55xx_tag(blocks, max); + int res = clone_t55xx_tag(blocks, max); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf indala read`") "to verify"); + return res; } static command_t CommandTable[] = { diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 1a25fca17..994c69a7d 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -275,7 +275,10 @@ static int CmdIOProxClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf io read`") "to verify"); + return res; } static command_t CommandTable[] = { diff --git a/client/cmdlfkeri.c b/client/cmdlfkeri.c index b0f45da04..3c7863361 100644 --- a/client/cmdlfkeri.c +++ b/client/cmdlfkeri.c @@ -181,7 +181,10 @@ static int CmdKeriDemod(const char *Cmd) { uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); //get internal id - uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32); + // uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32); + // Due to the 3 sync bits being at the start of the capture + // We can take the last 32bits as the internal ID. + uint32_t ID = raw2; ID &= 0x7FFFFFFF; /* @@ -277,7 +280,10 @@ static int CmdKeriClone(const char *Cmd) { print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf keri read`") "to verify"); + return res; } static int CmdKeriSim(const char *Cmd) { diff --git a/client/cmdlfmotorola.c b/client/cmdlfmotorola.c index 9f0ee1f41..c34b48d8e 100644 --- a/client/cmdlfmotorola.c +++ b/client/cmdlfmotorola.c @@ -177,7 +177,10 @@ static int CmdMotorolaClone(const char *Cmd) { blocks[2] = bytes_to_num(data + 4, 4); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf motorola read`") "to verify"); + return res; } static int CmdMotorolaSim(const char *Cmd) { diff --git a/client/cmdlfnedap.c b/client/cmdlfnedap.c index c3d6d1ace..a1d23cd91 100644 --- a/client/cmdlfnedap.c +++ b/client/cmdlfnedap.c @@ -475,6 +475,8 @@ static int CmdLFNedapClone(const char *Cmd) { } else { PrintAndLogEx(NORMAL, ""); } + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf nedap read`") "to verify"); return res; } diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c index 68be0e0bc..d288eeadc 100644 --- a/client/cmdlfnexwatch.c +++ b/client/cmdlfnexwatch.c @@ -158,8 +158,10 @@ static int CmdNexWatchClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); - + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf nexwatch read`") "to verify"); + return res; } static int CmdNexWatchSim(const char *Cmd) { diff --git a/client/cmdlfnoralsy.c b/client/cmdlfnoralsy.c index d7728a3d9..bbb7de0c9 100644 --- a/client/cmdlfnoralsy.c +++ b/client/cmdlfnoralsy.c @@ -169,7 +169,10 @@ static int CmdNoralsyClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf noralsy read`") "to verify"); + return res; } static int CmdNoralsySim(const char *Cmd) { diff --git a/client/cmdlfpac.c b/client/cmdlfpac.c index 24c549a4b..9ac9aa511 100644 --- a/client/cmdlfpac.c +++ b/client/cmdlfpac.c @@ -239,7 +239,10 @@ static int CmdPacClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pac read`") "to verify"); + return res; } static int CmdPacSim(const char *Cmd) { diff --git a/client/cmdlfparadox.c b/client/cmdlfparadox.c index 29e247b59..c540290f8 100644 --- a/client/cmdlfparadox.c +++ b/client/cmdlfparadox.c @@ -36,7 +36,7 @@ static int usage_lf_paradox_clone(void) { PrintAndLogEx(NORMAL, " b : raw hex data. 12 bytes max"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf paradox clone 0f55555695596a6a9999a59a"); + PrintAndLogEx(NORMAL, " lf paradox clone b 0f55555695596a6a9999a59a"); return PM3_SUCCESS; } @@ -169,7 +169,10 @@ static int CmdParadoxClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf paradox read`") "to verify"); + return res; } static int CmdParadoxSim(const char *Cmd) { diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index e4a14a47e..ddcad195d 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -11,6 +11,7 @@ #include "cmdlfpcf7931.h" #include +#include #include "cmdparser.h" // command_t #include "comms.h" @@ -36,7 +37,7 @@ int pcf7931_resetConfig() { configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY; configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; - return 0; + return PM3_SUCCESS; } int pcf7931_printConfig() { @@ -44,7 +45,7 @@ int pcf7931_printConfig() { PrintAndLogEx(NORMAL, "Tag initialization delay : %d us", configPcf.InitDelay); PrintAndLogEx(NORMAL, "Offset low pulses width : %d us", configPcf.OffsetWidth); PrintAndLogEx(NORMAL, "Offset low pulses position : %d us", configPcf.OffsetPosition); - return 0; + return PM3_SUCCESS; } static int usage_pcf7931_read() { @@ -54,7 +55,7 @@ static int usage_pcf7931_read() { PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf pcf7931 read"); - return 0; + return PM3_SUCCESS; } static int usage_pcf7931_write() { @@ -67,7 +68,7 @@ static int usage_pcf7931_write() { PrintAndLogEx(NORMAL, " data one byte of data (hex)"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf pcf7931 write 2 1 FF"); - return 0; + return PM3_SUCCESS; } static int usage_pcf7931_config() { @@ -87,30 +88,30 @@ static int usage_pcf7931_config() { PrintAndLogEx(NORMAL, " lf pcf7931 config r"); PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 20000"); PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 17500 -10 30"); - return 0; + return PM3_SUCCESS; } static int CmdLFPCF7931Read(const char *Cmd) { - uint8_t ctmp = param_getchar(Cmd, 0); - if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_read(); + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_pcf7931_read(); PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { PrintAndLogEx(WARNING, "command execution time out"); - return 1; + return PM3_ETIMEOUT; } - return 0; + return PM3_SUCCESS; } static int CmdLFPCF7931Config(const char *Cmd) { - uint8_t ctmp = param_getchar(Cmd, 0); + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); if (ctmp == 0) return pcf7931_printConfig(); - if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_config(); - if (ctmp == 'R' || ctmp == 'r') return pcf7931_resetConfig(); + if (ctmp == 'h') return usage_pcf7931_config(); + if (ctmp == 'r') return pcf7931_resetConfig(); if (param_gethex(Cmd, 0, configPcf.Pwd, 14)) return usage_pcf7931_config(); @@ -119,13 +120,13 @@ static int CmdLFPCF7931Config(const char *Cmd) { configPcf.OffsetPosition = (int)(param_get32ex(Cmd, 3, 0, 10) & 0xFFFF); pcf7931_printConfig(); - return 0; + return PM3_SUCCESS; } static int CmdLFPCF7931Write(const char *Cmd) { - uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); + uint8_t ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') return usage_pcf7931_write(); uint8_t block = 0, bytepos = 0, data = 0; @@ -136,9 +137,9 @@ static int CmdLFPCF7931Write(const char *Cmd) { data = param_get8ex(Cmd, 2, 0, 16); - PrintAndLogEx(NORMAL, "Writing block: %d", block); - PrintAndLogEx(NORMAL, " pos: %d", bytepos); - PrintAndLogEx(NORMAL, " data: 0x%02X", data); + PrintAndLogEx(INFO, "Writing block: %d", block); + PrintAndLogEx(INFO, " pos: %d", bytepos); + PrintAndLogEx(INFO, " data: 0x%02X", data); uint32_t buf[10]; // TODO sparse struct, 7 *bytes* then words at offset 4*7! memcpy(buf, configPcf.Pwd, sizeof(configPcf.Pwd)); @@ -147,9 +148,11 @@ static int CmdLFPCF7931Write(const char *Cmd) { buf[9] = configPcf.InitDelay; clearCommandBuffer(); - SendCommandOLD(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf)); - //no ack? - return 0; + SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf)); + + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pcf7931 read`") "to verify"); + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -163,7 +166,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdLFPCF7931(const char *Cmd) { diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index a0619d794..9f00dbdce 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -136,7 +136,10 @@ static int CmdPrescoClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf presco read`") "to verify"); + return res; } // takes base 12 ID converts to hex diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index 5737c87b9..14357201a 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -250,7 +250,10 @@ static int CmdPyramidClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pyramid read`") "to verify"); + return res; } static int CmdPyramidSim(const char *Cmd) { diff --git a/client/cmdlfsecurakey.c b/client/cmdlfsecurakey.c index ef4b5be8e..0061d56c4 100644 --- a/client/cmdlfsecurakey.c +++ b/client/cmdlfsecurakey.c @@ -168,7 +168,10 @@ static int CmdSecurakeyClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf securakey read`") "to verify"); + return res; } static int CmdSecurakeySim(const char *Cmd) { diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index f25626d94..c88b8a051 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -1028,7 +1028,6 @@ void T55xx_Print_DownlinkMode(uint8_t downlink_mode) { PrintAndLogEx(NORMAL, msg); } - static int CmdT55xxDetect(const char *Cmd) { bool errors = false; diff --git a/client/cmdlfti.c b/client/cmdlfti.c index cf01abb73..8507fa36a 100644 --- a/client/cmdlfti.c +++ b/client/cmdlfti.c @@ -296,6 +296,8 @@ static int CmdTIWrite(const char *Cmd) { } clearCommandBuffer(); SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf ti read`") "to verify"); return PM3_SUCCESS; } diff --git a/client/cmdlfverichip.c b/client/cmdlfverichip.c index fb2e4e777..91b49b8f4 100644 --- a/client/cmdlfverichip.c +++ b/client/cmdlfverichip.c @@ -121,7 +121,10 @@ static int CmdVerichipClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Verichip to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf verichip read`") "to verify"); + return res; } static int CmdVerichipSim(const char *Cmd) { diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index 69d8aee65..407c28f7e 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -117,6 +117,8 @@ static int CmdVikingClone(const char *Cmd) { PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); return PM3_ETIMEOUT; } + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf viking read`") "to verify"); return resp.status; } diff --git a/client/cmdlfvisa2000.c b/client/cmdlfvisa2000.c index 551a1efbb..1a628e51d 100644 --- a/client/cmdlfvisa2000.c +++ b/client/cmdlfvisa2000.c @@ -184,7 +184,10 @@ static int CmdVisa2kClone(const char *Cmd) { PrintAndLogEx(INFO, "Preparing to clone Visa2000 to T55x7 with CardId: %"PRIu64, id); print_blocks(blocks, ARRAYLEN(blocks)); - return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); + PrintAndLogEx(SUCCESS, "Done"); + PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf visa2000 read`") "to verify"); + return res; } static int CmdVisa2kSim(const char *Cmd) { diff --git a/client/cmdscript.c b/client/cmdscript.c index 322fd6adb..4f4a372d8 100644 --- a/client/cmdscript.c +++ b/client/cmdscript.c @@ -59,11 +59,13 @@ static int CmdScriptRun(const char *Cmd) { if ((!str_endswith(preferredName, ".cmd")) && (searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", true) == PM3_SUCCESS)) { int error; if (luascriptfile_idx == MAX_NESTED_LUASCRIPT) { - PrintAndLogEx(ERR, "Too many nested scripts, skipping %s\n", script_path); + PrintAndLogEx(ERR, "too many nested scripts, skipping %s\n", script_path); free(script_path); return PM3_EMALLOC; } - PrintAndLogEx(SUCCESS, "Executing Lua script: %s, args '%s'\n", script_path, arguments); + PrintAndLogEx(SUCCESS, "executing lua " _YELLOW_("%s"), script_path); + PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments); + luascriptfile_idx++; // create new Lua state @@ -94,7 +96,7 @@ static int CmdScriptRun(const char *Cmd) { if (error) { // if non-0, then an error // the top of the stack should be the error string if (!lua_isstring(lua_state, lua_gettop(lua_state))) - PrintAndLogEx(FAILED, "Error - but no error (?!)"); + PrintAndLogEx(FAILED, "error - but no error (?!)"); // get the top of the stack as the error and pop it off const char *str = lua_tostring(lua_state, lua_gettop(lua_state)); @@ -106,17 +108,22 @@ static int CmdScriptRun(const char *Cmd) { // close the Lua state lua_close(lua_state); luascriptfile_idx--; - PrintAndLogEx(SUCCESS, "\nFinished %s\n", preferredName); + PrintAndLogEx(SUCCESS, "\nfinished " _YELLOW_("%s"), preferredName); return PM3_SUCCESS; } + if ((!str_endswith(preferredName, ".lua")) && (searchFile(&script_path, CMD_SCRIPTS_SUBDIR, preferredName, ".cmd", true) == PM3_SUCCESS)) { - PrintAndLogEx(SUCCESS, "Executing Cmd script: %s, args '%s'\n", script_path, arguments); + + PrintAndLogEx(SUCCESS, "executing Cmd " _YELLOW_("%s"), script_path); + PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments); + int ret = push_cmdscriptfile(script_path, true); if (ret != PM3_SUCCESS) PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", script_path); free(script_path); return ret; } + // file not found, let's search again to display the error messages int ret = PM3_EUNDEF; if (!str_endswith(preferredName, ".cmd")) ret = searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", false); @@ -141,7 +148,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far PrintAndLogEx(NORMAL, "This is a feature to run Lua-scripts. You can place Lua-scripts within the luascripts/-folder. "); - return 0; + return PM3_SUCCESS; } /** diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 6422fe605..ba48fae96 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -216,23 +216,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { bool protocol_T15_present = false; if (T0 & 0x10) { - PrintAndLogEx(NORMAL, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); + PrintAndLogEx(INFO, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); T1len++; } if (T0 & 0x20) { - PrintAndLogEx(NORMAL, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]); + PrintAndLogEx(INFO, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]); T1len++; } if (T0 & 0x40) { - PrintAndLogEx(NORMAL, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]); + PrintAndLogEx(INFO, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]); T1len++; } if (T0 & 0x80) { uint8_t TD1 = atr[2 + T1len]; - PrintAndLogEx(NORMAL, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); + PrintAndLogEx(INFO, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); protocol_T0_present = false; if ((TD1 & 0x0f) == 0) { protocol_T0_present = true; @@ -244,20 +244,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { T1len++; if (TD1 & 0x10) { - PrintAndLogEx(NORMAL, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]); + PrintAndLogEx(INFO, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x20) { - PrintAndLogEx(NORMAL, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]); + PrintAndLogEx(INFO, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x40) { - PrintAndLogEx(NORMAL, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]); + PrintAndLogEx(INFO, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x80) { uint8_t TDi = atr[2 + T1len + TD1len]; - PrintAndLogEx(NORMAL, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); + PrintAndLogEx(INFO, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); if ((TDi & 0x0f) == 0) { protocol_T0_present = true; } @@ -271,20 +271,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { while (nextCycle) { nextCycle = false; if (TDi & 0x10) { - PrintAndLogEx(NORMAL, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x20) { - PrintAndLogEx(NORMAL, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x40) { - PrintAndLogEx(NORMAL, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x80) { TDi = atr[2 + T1len + TD1len + TDilen]; - PrintAndLogEx(NORMAL, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f); + PrintAndLogEx(INFO, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f); TDilen++; nextCycle = true; @@ -314,7 +314,7 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); if (K > 0) - PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); if (K > 1) { PrintAndLogEx(INFO, "\tHistorical bytes"); @@ -361,7 +361,9 @@ static int smart_responseEx(uint8_t *data, bool silent) { if (needGetData) { int len = data[datalen - 1]; + if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); + uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len}; clearCommandBuffer(); SendCommandOLD(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus)); @@ -740,10 +742,9 @@ static int CmdSmartInfo(const char *Cmd) { PrintAndLogEx(INFO, "--- Smartcard Information ---------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); - PrintAndLogEx(INFO, "\nhttp://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len)); + PrintAndLogEx(INFO, "http://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len)); // print ATR - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "ATR"); PrintATR(card.atr, card.atr_len); @@ -756,14 +757,14 @@ static int CmdSmartInfo(const char *Cmd) { if (GetATRTA1(card.atr, card.atr_len) == 0x11) PrintAndLogEx(INFO, "Using default values..."); - PrintAndLogEx(NORMAL, "\t- Di %d", Di); - PrintAndLogEx(NORMAL, "\t- Fi %d", Fi); - PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F); + PrintAndLogEx(INFO, "\t- Di %d", Di); + PrintAndLogEx(INFO, "\t- Fi %d", Fi); + PrintAndLogEx(INFO, "\t- F %.1f MHz", F); if (Di && Fi) { - PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi / Di); - PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di)); - PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F); + PrintAndLogEx(INFO, "\t- Cycles/ETU %d", Fi / Di); + PrintAndLogEx(INFO, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di)); + PrintAndLogEx(INFO, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F); } else { PrintAndLogEx(WARNING, "\t- Di or Fi is RFU."); }; @@ -1156,11 +1157,12 @@ int CmdSmartcard(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } -int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + *dataoutlen = 0; if (activateCard) - smart_select(false, NULL); + smart_select(true, NULL); PrintAndLogEx(DEBUG, "APDU SC"); @@ -1168,10 +1170,11 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave if (activateCard) { flags |= SC_SELECT | SC_CONNECT; } + clearCommandBuffer(); SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen); - int len = smart_responseEx(dataout, true); + int len = smart_responseEx(dataout, silent); if (len < 0) { return 1; @@ -1189,7 +1192,7 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave // something fishy: we have only 5 bytes but we put datainlen in arg1? SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data)); - len = smart_responseEx(dataout, true); + len = smart_responseEx(dataout, silent); } *dataoutlen = len; @@ -1204,6 +1207,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) { SendCommandNG(CMD_SMART_ATR, NULL, 0); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return false; } diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index 74c305a0d..798ea4678 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -17,6 +17,6 @@ int CmdSmartcard(const char *Cmd); bool smart_select(bool silent, smart_card_atr_t *atr); -int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); #endif diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 5bf330fe4..fe5ff3a31 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -305,7 +305,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea break; case ECC_CONTACT: if (IfPm3Smartcard()) - res = ExchangeAPDUSC(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + res = ExchangeAPDUSC(true, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); else res = 1; if (res) { diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 31085a629..388cc029e 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -544,8 +544,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, return -5; } - uint64_t t2 = msclock(); - float bruteforce_per_second = (float)KEYS_IN_BLOCK / (float)(t2 - start_time) * 1000.0; + float bruteforce_per_second = (float)KEYS_IN_BLOCK / (msclock() - start_time) * 1000.0; if ( i + 1 % 10 == 0) PrintAndLogEx(INFO, " %6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt , bruteforce_per_second, (keycnt-i) / bruteforce_per_second); @@ -676,6 +675,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl //flush queue while (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + free(mem); return PM3_EOPABORTED; } @@ -695,6 +695,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6) ); if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, "SPIFFS upload failed"); + free(mem); return res; } @@ -717,11 +718,12 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl ); return PM3_SUCCESS; } else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { + free(mem); return res; } // if (i%10 == 0) { - float bruteforce_per_second = (float)i + max_keys_chunk / (float)(msclock() - start_time) * 1000.0; + float bruteforce_per_second = (float)i + max_keys_chunk / (msclock() - start_time) * 1000.0; PrintAndLogEx(INFO, "Chunk %6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt-i) / bruteforce_per_second); // } } diff --git a/common/cardhelper.c b/common/cardhelper.c new file mode 100644 index 000000000..93e361f60 --- /dev/null +++ b/common/cardhelper.c @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// Iceman, February 2020 +// +// 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. +//----------------------------------------------------------------------------- +// Support functions for smart card +//----------------------------------------------------------------------------- +#include "cardhelper.h" +#include +#include +#include "cmdparser.h" +#include "cmdsmartcard.h" +#include "ui.h" +#include "util.h" + +#define CARD_INS_DECRYPT 0x01 +#define CARD_INS_ENCRYPT 0x02 +#define CARD_INS_DECODE 0x06 +static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// look for CryptoHelper +bool IsCryptoHelperPresent(void) { + + if (IfPm3Smartcard()) { + int resp_len = 0; + uint8_t version[] = {0x96, 0x69, 0x00, 0x00, 0x00}; + uint8_t resp[20] = {0}; + ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); + + if (strstr("CryptoHelper", (char*)resp) == 0) { + PrintAndLogEx(INFO, "Found smart card helper"); + return true; + } else { + return false; + } + } else { + return false; + } +} + +static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) { + int resp_len = 0; + uint8_t dec[11] = {0}; + + cmd[1] = ins; + memcpy(cmd + 5, src, 8); + + ExchangeAPDUSC(true, cmd, sizeof(cmd), false, true, dec, sizeof(dec), &resp_len); + + if (resp_len == 10) { + memcpy(dest, dec, 8); + return true; + } + return false; +} + +bool Decrypt(uint8_t *src, uint8_t *dest){ + return executeCrypto(CARD_INS_DECRYPT, src, dest); +} + +bool Encrypt(uint8_t *src, uint8_t *dest){ + return executeCrypto(CARD_INS_ENCRYPT, src, dest); +} + +void DecodeBlock6(uint8_t *src) { + int resp_len = 0; + uint8_t resp[254] = {0}; + + uint8_t c[] = {0x96, CARD_INS_DECODE, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(c + 6, src, 8); + + // first part + ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); + PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); + + // second part + c[5] = 0x02; + ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len); + PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); +} + diff --git a/common/cardhelper.h b/common/cardhelper.h new file mode 100644 index 000000000..14ae23d1f --- /dev/null +++ b/common/cardhelper.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Iceman, February 2020 +// +// 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. +//----------------------------------------------------------------------------- +// Utility functions used in many places, not specific to any piece of code. +//----------------------------------------------------------------------------- + +#ifndef __CARDHELPER_H +#define __CARDHELPER_H + +#include +#include "common.h" + +bool IsCryptoHelperPresent(void); +bool Encrypt(uint8_t *src, uint8_t *dest); +bool Decrypt(uint8_t *src, uint8_t *dest); +void DecodeBlock6(uint8_t *src); +#endif