From a1dd7c20209aab4518328757d88107c30334b3d2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 15 Feb 2018 11:47:34 +0100 Subject: [PATCH] chg: 'hf list mf' - adapted the output from 16bytes rows to 18 in order to make output more easily to compare --- client/cmdhf.c | 34 +++++++++++++++++----------------- client/cmdhflist.c | 37 ++++++++++++------------------------- client/mfkey.c | 6 +++--- client/util.c | 7 +++++++ client/util.h | 1 + 5 files changed, 40 insertions(+), 45 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 86f2c114a..3156ec209 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -187,19 +187,20 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui //2 Not crc-command //--- Draw the data column - char line[16][110]; + char line[18][110]; - for (int j = 0; j < data_len && j/16 < 16; j++) { + for (int j = 0; j < data_len && j/18 < 18; j++) { - uint8_t parityBits = parityBytes[j>>3]; + uint8_t parityBits = parityBytes[j >> 3]; if (protocol != LEGIC && protocol != ISO_14443B && protocol != ISO_7816_4 && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); + + snprintf(line[j/18]+(( j % 18) * 4),110, "%02x! ", frame[j]); } else { - snprintf(line[j/16]+(( j % 16) * 4),110, "%02x ", frame[j]); + snprintf(line[j/18]+(( j % 18) * 4),110, "%02x ", frame[j]); } } @@ -207,9 +208,9 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (markCRCBytes) { //CRC-command if(crcStatus == 0 || crcStatus == 1) { - char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); + char *pos1 = line[(data_len-2)/18]+(((data_len-2) % 18) * 4); (*pos1) = '['; - char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); + char *pos2 = line[(data_len)/18]+(((data_len) % 18) * 4); sprintf(pos2, "%c", ']'); } } @@ -245,10 +246,10 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } - int num_lines = MIN((data_len - 1)/16 + 1, 16); + int num_lines = MIN((data_len - 1)/18 + 1, 18); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLog(" %10u | %10u | %s |%-64s | %s| %s", + PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), (isResponse ? "Tag" : "Rdr"), @@ -256,7 +257,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); } else { - PrintAndLog(" | | |%-64s | %s| %s", + PrintAndLog(" | | |%-72s | %s| %s", line[j], (j == num_lines-1) ? crc : " ", (j == num_lines-1) ? explanation : ""); @@ -266,14 +267,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { memset(explanation, 0x00, sizeof(explanation)); if (!isResponse) { - explanation[0] = '>'; - annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen); + annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen); } uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen); - PrintAndLog(" | * | dec |%-64s | %-4s| %s", - sprint_hex(mfData, mfDataLen), + PrintAndLog(" | | * |%-72s | %-4s| %s", + sprint_hex_inrow_spaces(mfData, mfDataLen, 2), (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), - (true) ? explanation : ""); + explanation); }; if (is_last_record(tracepos, trace, traceLen)) return traceLen; @@ -486,8 +486,8 @@ int CmdHFList(const char *Cmd) { PrintAndLog("ISO18092 / FeliCa - Timings are not as accurate"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); - PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); + PrintAndLog("------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------"); ClearAuthData(); while(tracepos < traceLen) { diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 882bb3303..6c3dd1393 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -48,8 +48,7 @@ uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* d, uint8_t n) { return check_crc(CRC_14443_A, d, n); } -uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) -{ +uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { switch(MifareAuthState) { case masNone: case masError: @@ -84,8 +83,7 @@ uint8_t iso15693_CRC_check(uint8_t* d, uint8_t n) { * 1 : CRC-command, CRC ok * 2 : Not crc-command */ -uint8_t iclass_CRC_check(bool isResponse, uint8_t* d, uint8_t n) -{ +uint8_t iclass_CRC_check(bool isResponse, uint8_t* d, uint8_t n) { //CRC commands (and responses) are all at least 4 bytes if (n < 4) return 2; @@ -632,11 +630,10 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96); mfLastKey = GetCrypto1ProbableKey(&AuthData); - PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |", + PrintAndLog(" | | * |%49s %012"PRIx64" prng %s | |", + "key", mfLastKey, - validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD", - AuthData.ks2, - AuthData.ks3); + validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD"); AuthData.first_auth = false; @@ -650,12 +647,8 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes // check last used key if (mfLastKey) { if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) { - PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |", - mfLastKey, - AuthData.ks2, - AuthData.ks3); - - traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); + PrintAndLog(" | | * |%60s %012"PRIx64"| |", "last used key", mfLastKey); + traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); }; } @@ -663,10 +656,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes if (!traceCrypto1) { for (int i = 0; i < MIFARE_DEFAULTKEYS_SIZE; i++){ if (NestedCheckKey(g_mifare_default_keys[i], &AuthData, cmd, cmdsize, parity)) { - PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |", - g_mifare_default_keys[i], - AuthData.ks2, - AuthData.ks3); + PrintAndLog(" | | * |%61s %012"PRIx64"| |", "key", g_mifare_default_keys[i]); mfLastKey = g_mifare_default_keys[i]; traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); @@ -686,17 +676,15 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes uint32_t ks3 = AuthData.at_enc ^ prng_successor(ntx, 96); struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3); memcpy(mfData, cmd, cmdsize); - mf_crypto1_decrypt(pcs, mfData, cmdsize, 0); - + mf_crypto1_decrypt(pcs, mfData, cmdsize, 0); crypto1_destroy(pcs); if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && check_crc(CRC_14443_A, mfData, cmdsize)) { AuthData.ks2 = ks2; AuthData.ks3 = ks3; - AuthData.nt = ntx; mfLastKey = GetCrypto1ProbableKey(&AuthData); - PrintAndLog(" | * | key | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |", + PrintAndLog(" | | * | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |", mfLastKey, AuthData.ks2, AuthData.ks3); @@ -799,7 +787,6 @@ bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, memcpy(buf, cmd, cmdsize); mf_crypto1_decrypt(pcs, buf, cmdsize, 0); - crypto1_destroy(pcs); if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) @@ -811,7 +798,6 @@ bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, AuthData.nt = nt1; AuthData.ks2 = AuthData.ar_enc ^ ar; AuthData.ks3 = AuthData.at_enc ^ at; - return true; } @@ -820,10 +806,11 @@ bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01)) return false; } - return true; } +// Another implementation of mfkey64 attack, more "valid" than "probable" +// uint64_t GetCrypto1ProbableKey(TAuthData *ad) { struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3); lfsr_rollback_word(revstate, 0, 0); diff --git a/client/mfkey.c b/client/mfkey.c index 5f618f7d1..b35a3104c 100644 --- a/client/mfkey.c +++ b/client/mfkey.c @@ -153,9 +153,9 @@ bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) { // recover key from reader response and tag response of one authentication sequence int mfkey64(nonces_t data, uint64_t *outputkey){ - uint64_t key = 0; // recovered key - uint32_t ks2; // keystream used to encrypt reader response - uint32_t ks3; // keystream used to encrypt tag response + uint64_t key = 0; // recovered key + uint32_t ks2; // keystream used to encrypt reader response + uint32_t ks3; // keystream used to encrypt tag response struct Crypto1State *revstate; // Extract the keystream from the messages diff --git a/client/util.c b/client/util.c index 49e2c5f24..74bf5c1bd 100644 --- a/client/util.c +++ b/client/util.c @@ -181,6 +181,13 @@ char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t mi char *sprint_hex_inrow(const uint8_t *data, const size_t len) { return sprint_hex_inrow_ex(data, len, 0); } +char *sprint_hex_inrow_spaces(const uint8_t *data, const size_t len, size_t spaces_between) { + static char buf[1025] = {0}; + hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, spaces_between, true); + return buf; +} + + char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks) { diff --git a/client/util.h b/client/util.h index 965262410..185000081 100644 --- a/client/util.h +++ b/client/util.h @@ -185,6 +185,7 @@ extern void print_hex_break(const uint8_t *data, const size_t len, const uint8_t extern char *sprint_hex(const uint8_t * data, const size_t len); extern char *sprint_hex_inrow(const uint8_t *data, const size_t len); extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len); +extern char *sprint_hex_inrow_spaces(const uint8_t *data, const size_t len, size_t spaces_between); extern char *sprint_bin(const uint8_t * data, const size_t len); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_hex_ascii(const uint8_t *data, const size_t len);