chg: 'hf list mf' - adapted the output from 16bytes rows to 18 in order to make output more easily to compare

This commit is contained in:
iceman1001 2018-02-15 11:47:34 +01:00
parent 103e0b5191
commit a1dd7c2020
5 changed files with 40 additions and 45 deletions

View file

@ -187,19 +187,20 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
//2 Not crc-command //2 Not crc-command
//--- Draw the data column //--- 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 && if (protocol != LEGIC &&
protocol != ISO_14443B && protocol != ISO_14443B &&
protocol != ISO_7816_4 && protocol != ISO_7816_4 &&
(isResponse || protocol == ISO_14443A) && (isResponse || protocol == ISO_14443A) &&
(oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { (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 { } 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) { if (markCRCBytes) {
//CRC-command //CRC-command
if(crcStatus == 0 || crcStatus == 1) { 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) = '['; (*pos1) = '[';
char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); char *pos2 = line[(data_len)/18]+(((data_len) % 18) * 4);
sprintf(pos2, "%c", ']'); 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++) { for (int j = 0; j < num_lines ; j++) {
if (j == 0) { if (j == 0) {
PrintAndLog(" %10u | %10u | %s |%-64s | %s| %s", PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s",
(timestamp - first_timestamp), (timestamp - first_timestamp),
(EndOfTransmissionTimestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp),
(isResponse ? "Tag" : "Rdr"), (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) ? crc : " ",
(j == num_lines-1) ? explanation : ""); (j == num_lines-1) ? explanation : "");
} else { } else {
PrintAndLog(" | | |%-64s | %s| %s", PrintAndLog(" | | |%-72s | %s| %s",
line[j], line[j],
(j == num_lines-1) ? crc : " ", (j == num_lines-1) ? crc : " ",
(j == num_lines-1) ? explanation : ""); (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)) { if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) {
memset(explanation, 0x00, sizeof(explanation)); memset(explanation, 0x00, sizeof(explanation));
if (!isResponse) { if (!isResponse) {
explanation[0] = '>'; annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen);
annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen);
} }
uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen); uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen);
PrintAndLog(" | * | dec |%-64s | %-4s| %s", PrintAndLog(" | | * |%-72s | %-4s| %s",
sprint_hex(mfData, mfDataLen), sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
(true) ? explanation : ""); explanation);
}; };
if (is_last_record(tracepos, trace, traceLen)) return traceLen; 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("ISO18092 / FeliCa - Timings are not as accurate");
PrintAndLog(""); PrintAndLog("");
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation");
PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); PrintAndLog("------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------");
ClearAuthData(); ClearAuthData();
while(tracepos < traceLen) { while(tracepos < traceLen) {

View file

@ -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); 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) { switch(MifareAuthState) {
case masNone: case masNone:
case masError: case masError:
@ -84,8 +83,7 @@ uint8_t iso15693_CRC_check(uint8_t* d, uint8_t n) {
* 1 : CRC-command, CRC ok * 1 : CRC-command, CRC ok
* 2 : Not crc-command * 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 //CRC commands (and responses) are all at least 4 bytes
if (n < 4) return 2; 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); AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96);
mfLastKey = GetCrypto1ProbableKey(&AuthData); mfLastKey = GetCrypto1ProbableKey(&AuthData);
PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |", PrintAndLog(" | | * |%49s %012"PRIx64" prng %s | |",
"key",
mfLastKey, mfLastKey,
validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD", validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD");
AuthData.ks2,
AuthData.ks3);
AuthData.first_auth = false; AuthData.first_auth = false;
@ -650,11 +647,7 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
// check last used key // check last used key
if (mfLastKey) { if (mfLastKey) {
if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) { if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) {
PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |", PrintAndLog(" | | * |%60s %012"PRIx64"| |", "last used key", mfLastKey);
mfLastKey,
AuthData.ks2,
AuthData.ks3);
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); 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) { if (!traceCrypto1) {
for (int i = 0; i < MIFARE_DEFAULTKEYS_SIZE; i++){ for (int i = 0; i < MIFARE_DEFAULTKEYS_SIZE; i++){
if (NestedCheckKey(g_mifare_default_keys[i], &AuthData, cmd, cmdsize, parity)) { if (NestedCheckKey(g_mifare_default_keys[i], &AuthData, cmd, cmdsize, parity)) {
PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |", PrintAndLog(" | | * |%61s %012"PRIx64"| |", "key", g_mifare_default_keys[i]);
g_mifare_default_keys[i],
AuthData.ks2,
AuthData.ks3);
mfLastKey = g_mifare_default_keys[i]; mfLastKey = g_mifare_default_keys[i];
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
@ -687,16 +677,14 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3); struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3);
memcpy(mfData, cmd, cmdsize); memcpy(mfData, cmd, cmdsize);
mf_crypto1_decrypt(pcs, mfData, cmdsize, 0); mf_crypto1_decrypt(pcs, mfData, cmdsize, 0);
crypto1_destroy(pcs); crypto1_destroy(pcs);
if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && check_crc(CRC_14443_A, mfData, cmdsize)) { if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && check_crc(CRC_14443_A, mfData, cmdsize)) {
AuthData.ks2 = ks2; AuthData.ks2 = ks2;
AuthData.ks3 = ks3; AuthData.ks3 = ks3;
AuthData.nt = ntx; AuthData.nt = ntx;
mfLastKey = GetCrypto1ProbableKey(&AuthData); 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, mfLastKey,
AuthData.ks2, AuthData.ks2,
AuthData.ks3); AuthData.ks3);
@ -799,7 +787,6 @@ bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize,
memcpy(buf, cmd, cmdsize); memcpy(buf, cmd, cmdsize);
mf_crypto1_decrypt(pcs, buf, cmdsize, 0); mf_crypto1_decrypt(pcs, buf, cmdsize, 0);
crypto1_destroy(pcs); crypto1_destroy(pcs);
if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) 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.nt = nt1;
AuthData.ks2 = AuthData.ar_enc ^ ar; AuthData.ks2 = AuthData.ar_enc ^ ar;
AuthData.ks3 = AuthData.at_enc ^ at; AuthData.ks3 = AuthData.at_enc ^ at;
return true; 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)) if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01))
return false; return false;
} }
return true; return true;
} }
// Another implementation of mfkey64 attack, more "valid" than "probable"
//
uint64_t GetCrypto1ProbableKey(TAuthData *ad) { uint64_t GetCrypto1ProbableKey(TAuthData *ad) {
struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3); struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3);
lfsr_rollback_word(revstate, 0, 0); lfsr_rollback_word(revstate, 0, 0);

View file

@ -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) { char *sprint_hex_inrow(const uint8_t *data, const size_t len) {
return sprint_hex_inrow_ex(data, len, 0); 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) { char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks) {

View file

@ -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(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(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_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(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_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); extern char *sprint_hex_ascii(const uint8_t *data, const size_t len);