From f8ada309e9e521b0e57f67fad111ae1500b660f4 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Tue, 15 Dec 2015 08:51:29 +0100 Subject: [PATCH] ADD: @pwpiwi 's latest code from his 'hardnested' branch. --- armsrc/Makefile | 3 +- armsrc/iso14443a.c | 33 +---- armsrc/iso14443a.h | 3 - armsrc/mifarecmd.c | 9 +- armsrc/mifareutil.c | 11 +- client/Makefile | 1 + client/cmdhfmf.c | 29 +++- client/cmdhfmfhard.c | 316 +++++++++++++++++++++++++++++++++++-------- client/cmdhfmfhard.h | 2 +- 9 files changed, 298 insertions(+), 109 deletions(-) diff --git a/armsrc/Makefile b/armsrc/Makefile index ddcff33b..f4e7495d 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -60,7 +60,8 @@ ARMSRC = fpgaloader.c \ iclass.c \ BigBuf.c \ optimized_cipher.c \ - hfsnoop.c + hfsnoop.c \ + parity.c # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 29d9728a..2eb280e1 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -20,6 +20,8 @@ #include "crapto1.h" #include "mifareutil.h" #include "BigBuf.h" +#include "parity.h" + static uint32_t iso14a_timeout; int rsamples = 0; uint8_t trigger = 0; @@ -121,26 +123,6 @@ static uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 -const uint8_t OddByteParity[256] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 -}; - - void iso14a_set_trigger(bool enable) { trigger = enable; } @@ -178,11 +160,6 @@ void iso14a_set_ATS_timeout(uint8_t *ats) { // Generate the parity value for a byte sequence // //----------------------------------------------------------------------------- -byte_t oddparity (const byte_t bt) -{ - return OddByteParity[bt]; -} - void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) { uint16_t paritybit_cnt = 0; @@ -191,7 +168,7 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) for (uint16_t i = 0; i < iLen; i++) { // Generate the parity bits - parityBits |= ((OddByteParity[pbtCmd[i]]) << (7-paritybit_cnt)); + parityBits |= ((oddparity8(pbtCmd[i])) << (7-paritybit_cnt)); if (paritybit_cnt == 7) { par[paritybyte_cnt] = parityBits; // save 8 Bits parity parityBits = 0; // and advance to next Parity Byte @@ -3172,7 +3149,7 @@ void RAMFUNC SniffMifare(uint8_t param) { if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, TRUE)) break; /* And ready to receive another command. */ - UartReset(); + UartInit(receivedCmd, receivedCmdPar); /* And also reset the demod code */ DemodReset(); @@ -3189,10 +3166,8 @@ void RAMFUNC SniffMifare(uint8_t param) { // And ready to receive another response. DemodReset(); - // And reset the Miller decoder including its (now outdated) input buffer UartInit(receivedCmd, receivedCmdPar); - // why not UartReset? } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index c9da0da7..44d5733a 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -13,7 +13,6 @@ #ifndef __ISO14443A_H #define __ISO14443A_H #include "common.h" -#include "mifare.h" #include "mifaresniff.h" typedef struct { @@ -71,8 +70,6 @@ typedef struct { } tUart; - -extern byte_t oddparity (const byte_t bt); extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); extern void AppendCrc14443a(uint8_t *data, int len); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index be25273d..a77a2dd3 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -18,6 +18,7 @@ #include "util.h" #include "crc.h" #include "protocols.h" +#include "parity.h" //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. @@ -591,9 +592,9 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ // Return 1 if the nonce is invalid else return 0 int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { - return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ - (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ - (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; + return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; } @@ -897,7 +898,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // Parity validity check for (j = 0; j < 4; j++) { - par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); + par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); } ncount = 0; diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 7546919d..f155a92d 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -18,6 +18,7 @@ #include "iso14443a.h" #include "crapto1.h" #include "mifareutil.h" +#include "parity.h" #include "des.h" int MF_DBGLEVEL = MF_DBG_ALL; @@ -50,7 +51,7 @@ void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, u data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; if((i&0x0007) == 0) par[i>>3] = 0; - par[i>>3] |= (((filter(pcs->odd) ^ oddparity(bt)) & 0x01)<<(7-(i&0x0007))); + par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); } return; } @@ -99,7 +100,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos)); } ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); @@ -193,7 +194,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN for (pos = 0; pos < 4; pos++) { mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity(nr[pos])) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7-pos)); } // Skip 32 bits in pseudo random generator @@ -204,7 +205,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN { nt = prng_successor(nt,8); mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); - par[0] |= (((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) << (7-pos)); + par[0] |= (((filter(pcs->odd) ^ oddparity8(nt & 0xff)) & 0x01) << (7-pos)); } // Transmit reader nonce and reader answer @@ -427,7 +428,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; - par[pos>>3] |= (((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); + par[pos>>3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); diff --git a/client/Makefile b/client/Makefile index 20273dd6..7ae23917 100644 --- a/client/Makefile +++ b/client/Makefile @@ -90,6 +90,7 @@ CMDSRCS = nonce2key/crapto1.c\ loclass/elite_crack.c\ loclass/fileutils.c\ mifarehost.c\ + parity.c\ crc.c \ crc16.c \ crc64.c \ diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 0a24f6da..d43a0ef2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -799,14 +799,16 @@ int CmdHF14AMfNestedHard(const char *Cmd) uint8_t trgBlockNo = 0; uint8_t trgKeyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint8_t trgkey[6] = {0, 0, 0, 0, 0, 0}; char ctmp; ctmp = param_getchar(Cmd, 0); + if (ctmp != 'R' && ctmp != 'r' && strlen(Cmd) < 20) { PrintAndLog("Usage:"); PrintAndLog(" hf mf hardnested "); - PrintAndLog(" [w] [s]"); - PrintAndLog(" or hf mf hardnested r"); + PrintAndLog(" [known target key (12 hex symbols)] [w] [s]"); + PrintAndLog(" or hf mf hardnested r [known target key]"); PrintAndLog(" "); PrintAndLog("Options: "); PrintAndLog(" w: Acquire nonces and write them to binary file nonces.bin"); @@ -817,17 +819,22 @@ int CmdHF14AMfNestedHard(const char *Cmd) PrintAndLog(" sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w"); PrintAndLog(" sample3: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s"); PrintAndLog(" sample4: hf mf hardnested r"); - + PrintAndLog(" "); + PrintAndLog("Add the known target key to check if it is present in the remaining key space:"); + PrintAndLog(" sample5: hf mf hardnested 0 A A0A1A2A3A4A5 4 A FFFFFFFFFFFF"); return 0; } + bool know_target_key = false; bool nonce_file_read = false; bool nonce_file_write = false; bool slow = false; if (ctmp == 'R' || ctmp == 'r') { - nonce_file_read = true; + if (!param_gethex(Cmd, 1, trgkey, 12)) { + know_target_key = true; + } } else { @@ -857,6 +864,12 @@ int CmdHF14AMfNestedHard(const char *Cmd) } uint16_t i = 5; + + if (!param_gethex(Cmd, 5, trgkey, 12)) { + know_target_key = true; + i++; + } + while ((ctmp = param_getchar(Cmd, i))) { if (ctmp == 's' || ctmp == 'S') { slow = true; @@ -870,12 +883,16 @@ int CmdHF14AMfNestedHard(const char *Cmd) } } - PrintAndLog("--target block no:%3d, target key type:%c, file action: %s, Slow: %s ", + PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s ", trgBlockNo, trgKeyType?'B':'A', + trgkey[0], trgkey[1], trgkey[2], trgkey[3], trgkey[4], trgkey[5], + know_target_key?"":" (not set)", nonce_file_write?"write":nonce_file_read?"read":"none", slow?"Yes":"No"); - int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_read, nonce_file_write, slow); + + int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, know_target_key?trgkey:NULL, nonce_file_read, nonce_file_write, slow); + if (isOK) { switch (isOK) { case 1 : PrintAndLog("Error: No response from Proxmark.\n"); break; diff --git a/client/cmdhfmfhard.c b/client/cmdhfmfhard.c index 6cd5a5b9..9a938d64 100644 --- a/client/cmdhfmfhard.c +++ b/client/cmdhfmfhard.c @@ -24,12 +24,13 @@ #include "ui.h" #include "util.h" #include "nonce2key/crapto1.h" +#include "parity.h" // uint32_t test_state_odd = 0; // uint32_t test_state_even = 0; -#define CONFIDENCE_THRESHOLD 0.99 // Collect nonces until we are certain enough that the following brute force is successfull -#define GOOD_BYTES_REQUIRED 25 +#define CONFIDENCE_THRESHOLD 0.95 // Collect nonces until we are certain enough that the following brute force is successfull +#define GOOD_BYTES_REQUIRED 60 static const float p_K[257] = { // the probability that a random nonce has a Sum Property == K @@ -90,8 +91,10 @@ static noncelist_t nonces[256]; static uint16_t first_byte_Sum = 0; static uint16_t first_byte_num = 0; static uint16_t num_good_first_bytes = 0; +static uint64_t maximum_states = 0; +static uint64_t known_target_key; -#define MAX_BEST_BYTES 40 +#define MAX_BEST_BYTES 256 static uint8_t best_first_bytes[MAX_BEST_BYTES]; @@ -116,10 +119,10 @@ typedef struct { } statelist_t; -partial_indexed_statelist_t partial_statelist[17]; -partial_indexed_statelist_t statelist_bitflip; +static partial_indexed_statelist_t partial_statelist[17]; +static partial_indexed_statelist_t statelist_bitflip; -statelist_t *candidates = NULL; +static statelist_t *candidates = NULL; static int add_nonce(uint32_t nonce_enc, uint8_t par_enc) @@ -130,12 +133,12 @@ static int add_nonce(uint32_t nonce_enc, uint8_t par_enc) if (p1 == NULL) { // first nonce with this 1st byte first_byte_num++; - first_byte_Sum += parity((nonce_enc & 0xff000000) | (par_enc & 0x08) | 0x01); // 1st byte sum property. Note: added XOR 1 + first_byte_Sum += evenparity32((nonce_enc & 0xff000000) | (par_enc & 0x08)); // printf("Adding nonce 0x%08x, par_enc 0x%02x, parity(0x%08x) = %d\n", // nonce_enc, // par_enc, // (nonce_enc & 0xff000000) | (par_enc & 0x08) |0x01, - // parity((nonce_enc & 0xff000000) | (par_enc & 0x08) | 0x01)); + // parity((nonce_enc & 0xff000000) | (par_enc & 0x08)); } while (p1 != NULL && (p1->nonce_enc & 0x00ff0000) < (nonce_enc & 0x00ff0000)) { @@ -165,7 +168,7 @@ static int add_nonce(uint32_t nonce_enc, uint8_t par_enc) p2->par_enc = par_enc; nonces[first_byte].num++; - nonces[first_byte].Sum += parity((nonce_enc & 0x00ff0000) | (par_enc & 0x04) | 0x01); // 2nd byte sum property. Note: added XOR 1 + nonces[first_byte].Sum += evenparity32((nonce_enc & 0x00ff0000) | (par_enc & 0x04)); nonces[first_byte].updated = true; // indicates that we need to recalculate the Sum(a8) probability for this first byte return (1); // new nonce added @@ -183,6 +186,7 @@ static uint16_t PartialSumProperty(uint32_t state, odd_even_t odd_even) part_sum ^= filter(st); st = (st << 1) | ((j >> (3-i)) & 0x01) ; } + part_sum ^= 1; // XOR 1 cancelled out for the other 8 bits } else { for (uint16_t i = 0; i < 4; i++) { st = (st << 1) | ((j >> (3-i)) & 0x01) ; @@ -273,8 +277,8 @@ static void Tests() } // #define NUM_STATISTICS 100000 - // uint64_t statistics[257]; // uint32_t statistics_odd[17]; + // uint64_t statistics[257]; // uint32_t statistics_even[17]; // struct Crypto1State cs; // time_t time1 = clock(); @@ -366,13 +370,25 @@ static void Tests() // test_state_odd = pcs->odd & 0x00ffffff; // test_state_even = pcs->even & 0x00ffffff; crypto1_destroy(pcs); + pcs = crypto1_create(0xa6b9aa97b955); + printf("Tests: for key = 0xa6b9aa97b955:\nSum(a0) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n", + SumProperty(pcs), pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff); + crypto1_byte(pcs, (cuid >> 24) ^ best_first_bytes[0], true); + printf("After adding best first byte 0x%02x:\nSum(a8) = %d\nodd_state = 0x%06x\neven_state = 0x%06x\n", + best_first_bytes[0], + SumProperty(pcs), + pcs->odd & 0x00ffffff, pcs->even & 0x00ffffff); + //test_state_odd = pcs->odd & 0x00ffffff; + //test_state_even = pcs->even & 0x00ffffff; + crypto1_destroy(pcs); + printf("\nTests: number of states with BitFlipProperty: %d, (= %1.3f%% of total states)\n", statelist_bitflip.len[0], 100.0 * statelist_bitflip.len[0] / (1<<20)); printf("\nTests: Actual BitFlipProperties odd/even:\n"); for (uint16_t i = 0; i < 256; i++) { - printf("[%3d]:%c%c ", i, nonces[i].BitFlip[ODD_STATE]?'o':' ', nonces[i].BitFlip[EVEN_STATE]?'e':' '); + printf("[%02x]:%c%c ", i, nonces[i].BitFlip[ODD_STATE]?'o':' ', nonces[i].BitFlip[EVEN_STATE]?'e':' '); if (i % 8 == 7) { printf("\n"); } @@ -385,42 +401,46 @@ static void Tests() uint16_t best_sum = nonces[best_byte].Sum; uint16_t best_sum8 = nonces[best_byte].Sum8_guess; float confidence = nonces[best_byte].Sum8_prob; - printf("Byte: %02x, n = %2d, k = %2d, Sum(a8): %3d, Confidence: %2.1f%%\n", best_byte, best_num, best_sum, best_sum8, confidence*100); + printf("#%03d Byte: %02x, n = %2d, k = %2d, Sum(a8): %3d, Confidence: %2.1f%%\n", i, best_byte, best_num, best_sum, best_sum8, confidence*100); } + + // printf("\nTests: parity performance\n"); + // time_t time1p = clock(); + // uint32_t par_sum = 0; + // for (uint32_t i = 0; i < 100000000; i++) { + // par_sum += parity(i); + // } + // printf("parsum oldparity = %d, time = %1.5fsec\n", par_sum, (float)(clock() - time1p)/CLOCKS_PER_SEC); + + // time1p = clock(); + // par_sum = 0; + // for (uint32_t i = 0; i < 100000000; i++) { + // par_sum += evenparity32(i); + // } + // printf("parsum newparity = %d, time = %1.5fsec\n", par_sum, (float)(clock() - time1p)/CLOCKS_PER_SEC); + } -static void sort_best_first_bytes(void) +static int common_bits(uint8_t byte1, uint8_t byte2) { - // find the best choice for the very first byte (b) - float min_p_K = 1.0; - float max_prob_min_p_K = 0.0; - uint8_t best_byte = 0; - for (uint16_t i = 0; i < 256; i++ ) { - float prob1 = nonces[i].Sum8_prob; - uint16_t sum8 = nonces[i].Sum8_guess; - if (p_K[sum8] <= min_p_K && prob1 > CONFIDENCE_THRESHOLD) { - if (p_K[sum8] < min_p_K) { - min_p_K = p_K[sum8]; - best_byte = i; - max_prob_min_p_K = prob1; - } else if (prob1 > max_prob_min_p_K) { - max_prob_min_p_K = prob1; - best_byte = i; - } - } + uint8_t common_bits = byte1 ^ byte2; + uint8_t j = 0; + while ((common_bits & 0x01) == 0 && j < 8) { + j++; + common_bits >>= 1; } - best_first_bytes[0] = best_byte; - // printf("Best Byte = 0x%02x, Sum8=%d, prob=%1.3f\n", best_byte, nonces[best_byte].Sum8_guess, nonces[best_byte].Sum8_prob); - - // sort the most probable guesses as following bytes (b') + return j; +} + + +static void sort_best_first_bytes(void) +{ + // first, sort based on probability for correct guess for (uint16_t i = 0; i < 256; i++ ) { - if (i == best_first_bytes[0]) { - continue; - } - uint16_t j = 1; + uint16_t j = 0; float prob1 = nonces[i].Sum8_prob; - float prob2 = nonces[best_first_bytes[1]].Sum8_prob; + float prob2 = nonces[best_first_bytes[0]].Sum8_prob; while (prob1 < prob2 && j < MAX_BEST_BYTES-1) { prob2 = nonces[best_first_bytes[++j]].Sum8_prob; } @@ -431,6 +451,70 @@ static void sort_best_first_bytes(void) best_first_bytes[j] = i; } } + + // determine, how many are above the CONFIDENCE_THRESHOLD + uint16_t num_good_nonces = 0; + for (uint16_t i = 0; i < MAX_BEST_BYTES; i++) { + if (nonces[best_first_bytes[i]].Sum8_prob > CONFIDENCE_THRESHOLD) { + ++num_good_nonces; + } + } + + uint16_t best_first_byte = 0; + + // select the best possible first byte based on number of common bits with all {b'} + // uint16_t max_common_bits = 0; + // for (uint16_t i = 0; i < num_good_nonces; i++) { + // uint16_t sum_common_bits = 0; + // for (uint16_t j = 0; j < num_good_nonces; j++) { + // if (i != j) { + // sum_common_bits += common_bits(best_first_bytes[i],best_first_bytes[j]); + // } + // } + // if (sum_common_bits > max_common_bits) { + // max_common_bits = sum_common_bits; + // best_first_byte = i; + // } + // } + + // select best possible first byte {b} based on least likely sum/bitflip property + float min_p_K = 1.0; + for (uint16_t i = 0; i < num_good_nonces; i++ ) { + uint16_t sum8 = nonces[best_first_bytes[i]].Sum8_guess; + float bitflip_prob = 1.0; + if (nonces[best_first_bytes[i]].BitFlip[ODD_STATE] || nonces[best_first_bytes[i]].BitFlip[EVEN_STATE]) { + bitflip_prob = 0.09375; + } + if (p_K[sum8] * bitflip_prob <= min_p_K) { + min_p_K = p_K[sum8] * bitflip_prob; + best_first_byte = i; + } + } + + // use number of commmon bits as a tie breaker + uint16_t max_common_bits = 0; + for (uint16_t i = 0; i < num_good_nonces; i++) { + float bitflip_prob = 1.0; + if (nonces[best_first_bytes[i]].BitFlip[ODD_STATE] || nonces[best_first_bytes[i]].BitFlip[EVEN_STATE]) { + bitflip_prob = 0.09375; + } + if (p_K[nonces[best_first_bytes[i]].Sum8_guess] * bitflip_prob == min_p_K) { + uint16_t sum_common_bits = 0; + for (uint16_t j = 0; j < num_good_nonces; j++) { + sum_common_bits += common_bits(best_first_bytes[i],best_first_bytes[j]); + } + if (sum_common_bits > max_common_bits) { + max_common_bits = sum_common_bits; + best_first_byte = i; + } + } + } + + // swap best possible first bytes to the pole position + uint16_t temp = best_first_bytes[0]; + best_first_bytes[0] = best_first_bytes[best_first_byte]; + best_first_bytes[best_first_byte] = temp; + } @@ -512,7 +596,7 @@ static int read_nonce_file(void) } -int static acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_write, bool slow) +static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_write, bool slow) { clock_t time1 = clock(); bool initialize = true; @@ -617,10 +701,10 @@ int static acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ fclose(fnonces); } - PrintAndLog("Acquired a total of %d nonces in %1.1f seconds (%d nonces/minute)", + PrintAndLog("Acquired a total of %d nonces in %1.1f seconds (%0.0f nonces/minute)", total_num_nonces, ((float)clock()-time1)/CLOCKS_PER_SEC, - total_num_nonces*60*CLOCKS_PER_SEC/(clock()-time1)); + total_num_nonces*60.0*CLOCKS_PER_SEC/((float)clock()-time1)); return 0; } @@ -628,7 +712,7 @@ int static acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_ static int init_partial_statelists(void) { - const uint32_t sizes_odd[17] = { 125601, 0, 17607, 0, 73421, 0, 182033, 0, 248801, 0, 181737, 0, 74241, 0, 18387, 0, 126757 }; + const uint32_t sizes_odd[17] = { 126757, 0, 18387, 0, 74241, 0, 181737, 0, 248801, 0, 182033, 0, 73421, 0, 17607, 0, 125601 }; const uint32_t sizes_even[17] = { 125723, 0, 17867, 0, 74305, 0, 178707, 0, 248801, 0, 185063, 0, 73356, 0, 18127, 0, 126634 }; printf("Allocating memory for partial statelists...\n"); @@ -712,7 +796,7 @@ static void add_state(statelist_t *sl, uint32_t state, odd_even_t odd_even) } -uint32_t *find_first_state(uint32_t state, uint32_t mask, partial_indexed_statelist_t *sl, odd_even_t odd_even) +static uint32_t *find_first_state(uint32_t state, uint32_t mask, partial_indexed_statelist_t *sl, odd_even_t odd_even) { uint32_t *p = sl->index[odd_even][(state & mask) >> (20-STATELIST_INDEX_WIDTH)]; // first Bits as index @@ -738,7 +822,7 @@ static bool remaining_bits_match(uint8_t num_common_bits, uint8_t byte1, uint8_t uint32_t bit_diff = ((byte1 ^ byte2) << (17-j)) & 0x00010000; // difference of (j-1)th bit -> bit 16 uint32_t filter_diff = filter(state1 >> (4-j/2)) ^ filter(state2 >> (4-j/2)); // difference in filter function -> bit 0 uint32_t mask_y12_y13 = 0x000000c0 >> (j/2); - uint32_t state_diff = (state1 ^ state2) & mask_y12_y13; // difference in state bits 12 and 13 -> bits 6/7 ... 4/5 + uint32_t state_diff = (state1 ^ state2) & mask_y12_y13; // difference in state bits 12 and 13 -> bits 6/7 ... 3/4 uint32_t all_diff = parity(bit_diff | state_diff | filter_diff); // use parity function to XOR all 4 bits if (all_diff) { // invariant doesn't hold any more. Accept this state. // if ((odd_even == ODD_STATE && state1 == test_state_odd) @@ -848,6 +932,79 @@ static bool all_other_first_bytes_match(uint32_t state, odd_even_t odd_even) } +static bool all_bit_flips_match(uint32_t state, odd_even_t odd_even) +{ + for (uint16_t i = 0; i < 256; i++) { + if (nonces[i].BitFlip[odd_even] && i != best_first_bytes[0]) { + uint8_t j = 0; // number of common bits + uint8_t common_bits = best_first_bytes[0] ^ i; + uint32_t mask = 0xfffffff0; + if (odd_even == ODD_STATE) { + while ((common_bits & 0x01) == 0 && j < 8) { + j++; + common_bits >>= 1; + if (j % 2 == 0) { // the odd bits + mask >>= 1; + } + } + } else { + while ((common_bits & 0x01) == 0 && j < 8) { + j++; + common_bits >>= 1; + if (j % 2 == 1) { // the even bits + mask >>= 1; + } + } + } + mask &= 0x000fffff; + //printf("bytes 0x%02x and 0x%02x: %d common bits, mask = 0x%08x, state = 0x%08x, sum_a8 = %d", best_first_bytes[0], best_first_bytes[i], j, mask, state, sum_a8); + bool found_match = false; + uint32_t *p = find_first_state(state, mask, &statelist_bitflip, 0); + if (p != NULL) { + while ((state & mask) == (*p & mask) && (*p != 0xffffffff)) { + if (remaining_bits_match(j, best_first_bytes[0], i, state, (state&0x00fffff0) | *p, odd_even)) { + found_match = true; + // if ((odd_even == ODD_STATE && state == test_state_odd) + // || (odd_even == EVEN_STATE && state == test_state_even)) { + // printf("all_other_first_bytes_match(): %s test state: remaining bits matched. Bytes = %02x, %02x, Common Bits=%d, mask=0x%08x, PartSum(a8)=%d\n", + // odd_even==ODD_STATE?"odd":"even", best_first_bytes[0], best_first_bytes[i], j, mask, part_sum_a8); + // } + break; + } else { + // if ((odd_even == ODD_STATE && state == test_state_odd) + // || (odd_even == EVEN_STATE && state == test_state_even)) { + // printf("all_other_first_bytes_match(): %s test state: remaining bits didn't match. Bytes = %02x, %02x, Common Bits=%d, mask=0x%08x, PartSum(a8)=%d\n", + // odd_even==ODD_STATE?"odd":"even", best_first_bytes[0], best_first_bytes[i], j, mask, part_sum_a8); + // } + } + p++; + } + } else { + // if ((odd_even == ODD_STATE && state == test_state_odd) + // || (odd_even == EVEN_STATE && state == test_state_even)) { + // printf("all_other_first_bytes_match(): %s test state: couldn't find a matching state. Bytes = %02x, %02x, Common Bits=%d, mask=0x%08x, PartSum(a8)=%d\n", + // odd_even==ODD_STATE?"odd":"even", best_first_bytes[0], best_first_bytes[i], j, mask, part_sum_a8); + // } + } + if (!found_match) { + // if ((odd_even == ODD_STATE && state == test_state_odd) + // || (odd_even == EVEN_STATE && state == test_state_even)) { + // printf("all_other_first_bytes_match(): %s test state: Eliminated. Bytes = %02x, %02x, Common Bits = %d\n", odd_even==ODD_STATE?"odd":"even", best_first_bytes[0], best_first_bytes[i], j); + // } + return false; + } + } + + } + + return true; +} + + +#define INVALID_BIT (1<<30) +#define SET_INVALID(pstate) (*(pstate) |= INVALID_BIT) +#define IS_INVALID(state) (state & INVALID_BIT) + static int add_matching_states(statelist_t *candidates, uint16_t part_sum_a0, uint16_t part_sum_a8, odd_even_t odd_even) { uint32_t worstcase_size = 1<<20; @@ -863,15 +1020,20 @@ static int add_matching_states(statelist_t *candidates, uint16_t part_sum_a0, ui if (p2 != NULL) { while (((*p1 << 4) & search_mask) == (*p2 & search_mask) && *p2 != 0xffffffff) { if (all_other_first_bytes_match((*p1 << 4) | *p2, odd_even)) { + if (all_bit_flips_match((*p1 << 4) | *p2, odd_even)) { add_state(candidates, (*p1 << 4) | *p2, odd_even); } + } p2++; } } - p2 = candidates->states[odd_even]; - p2 += candidates->len[odd_even]; - *p2 = 0xffffffff; } + + // set end of list marker + uint32_t *p = candidates->states[odd_even]; + p += candidates->len[odd_even]; + *p = 0xffffffff; + candidates->states[odd_even] = realloc(candidates->states[odd_even], sizeof(uint32_t) * (candidates->len[odd_even] + 1)); return 0; @@ -906,22 +1068,39 @@ static void TestIfKeyExists(uint64_t key) uint32_t state_odd = pcs->odd & 0x00ffffff; uint32_t state_even = pcs->even & 0x00ffffff; - printf("Tests: searching for key %llx after first byte 0x%02x (state_odd = 0x%06x, state_even = 0x%06x) ...\n", key, best_first_bytes[0], state_odd, state_even); + //printf("Tests: searching for key %llx after first byte 0x%02x (state_odd = 0x%06x, state_even = 0x%06x) ...\n", key, best_first_bytes[0], state_odd, state_even); + uint64_t count = 0; for (statelist_t *p = candidates; p != NULL; p = p->next) { + bool found_odd = false; + bool found_even = false; uint32_t *p_odd = p->states[ODD_STATE]; uint32_t *p_even = p->states[EVEN_STATE]; while (*p_odd != 0xffffffff) { - if (*p_odd == state_odd) printf("o"); + if ((*p_odd & 0x00ffffff) == state_odd) { + found_odd = true; + break; + } p_odd++; } while (*p_even != 0xffffffff) { - if (*p_even == state_even) printf("e"); + if ((*p_even & 0x00ffffff) == state_even) { + found_even = true; + } p_even++; } - printf("|"); + count += (p_odd - p->states[ODD_STATE]) * (p_even - p->states[EVEN_STATE]); + if (found_odd && found_even) { + PrintAndLog("Key Found after testing %lld (2^%1.1f) out of %lld (2^%1.1f) keys. A brute force would have taken approx %lld minutes.", + count, log(count)/log(2), + maximum_states, log(maximum_states)/log(2), + (count>>22)/60); + crypto1_destroy(pcs); + return; + } } - printf("\n"); + + printf("Key NOT found!\n"); crypto1_destroy(pcs); } @@ -932,7 +1111,7 @@ static void generate_candidates(uint16_t sum_a0, uint16_t sum_a8) statelist_t *current_candidates = NULL; // estimate maximum candidate states - uint64_t maximum_states = 0; + maximum_states = 0; for (uint16_t sum_odd = 0; sum_odd <= 16; sum_odd += 2) { for (uint16_t sum_even = 0; sum_even <= 16; sum_even += 2) { if (sum_odd*(16-sum_even) + (16-sum_odd)*sum_even == sum_a0) { @@ -969,9 +1148,6 @@ static void generate_candidates(uint16_t sum_a0, uint16_t sum_a8) } printf("Number of remaining possible keys: %lld (2^%1.1f)\n", maximum_states, log(maximum_states)/log(2.0)); - TestIfKeyExists(0xffffffffffff); - TestIfKeyExists(0xa0a1a2a3a4a5); - } @@ -998,8 +1174,28 @@ static void Check_for_FilterFlipProperties(void) } -int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_read, bool nonce_file_write, bool slow) +static void brute_force(void) { + if (known_target_key != -1) { + PrintAndLog("Looking for known target key in remaining key space..."); + TestIfKeyExists(known_target_key); + return; + } else { + PrintAndLog("Brute Force phase is not implemented."); + return; + } + + +} + + +int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow) +{ + if (trgkey != NULL) { + known_target_key = bytes_to_num(trgkey, 6); + } else { + known_target_key = -1; + } // initialize the list of nonces for (uint16_t i = 0; i < 256; i++) { @@ -1021,7 +1217,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc if (read_nonce_file() != 0) { return 3; } - num_good_first_bytes = estimate_second_byte_sum(); + num_good_first_bytes = MIN(estimate_second_byte_sum(), GOOD_BYTES_REQUIRED); } else { // acquire nonces. uint16_t is_OK = acquire_nonces(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_write, slow); if (is_OK != 0) { @@ -1050,7 +1246,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc generate_candidates(first_byte_Sum, nonces[best_first_bytes[0]].Sum8_guess); - PrintAndLog("Brute force phase not yet implemented"); + brute_force(); return 0; } diff --git a/client/cmdhfmfhard.h b/client/cmdhfmfhard.h index 94c57717..024ad2be 100644 --- a/client/cmdhfmfhard.h +++ b/client/cmdhfmfhard.h @@ -8,4 +8,4 @@ // hf mf hardnested command //----------------------------------------------------------------------------- -int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, bool nonce_file_read, bool nonce_file_write, bool slow); +int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow); -- 2.39.2