diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index a54aebc61..0f762a8d6 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -101,16 +101,16 @@ static const uint8_t opt_select_LUT[256] = { /********************** the table above has been generated with this code: ******** #include "util.h" static void init_opt_select_LUT(void) { - for (int r = 0; r < 256; r++) { - uint8_t r_ls2 = r << 2; - uint8_t r_and_ls2 = r & r_ls2; - uint8_t r_or_ls2 = r | r_ls2; - uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); - uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r; - uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r; - opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1); - } - print_result("", opt_select_LUT, 256); + for (int r = 0; r < 256; r++) { + uint8_t r_ls2 = r << 2; + uint8_t r_and_ls2 = r & r_ls2; + uint8_t r_or_ls2 = r | r_ls2; + uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); + uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r; + uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r; + opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1); + } + print_result("", opt_select_LUT, 256); } ***********************************************************************************/ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 8aea8db6c..b21e8dbd7 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -133,7 +133,7 @@ static const manufactureName manufactureMapping[] = { { 0x61, "Wearlinks Technology Inc. China" }, { 0x62, "Userstar Information Systems Co., Ltd Taiwan" }, { 0x63, "Pragmatic Printing Ltd. UK" }, - { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico – LSI-TEC Brazil" }, + { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico - LSI-TEC Brazil" }, { 0x65, "Tendyron Corporation China" }, { 0x66, "MUTO Smart Co., Ltd. Korea" }, { 0x67, "ON Semiconductor USA" }, diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 82aba722e..99d6afd97 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1873,7 +1873,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { for (int j = 0; j < 2; j++) { if (e_sector[i].foundKey[j] == 1) { num_to_bytes(e_sector[i].Key[j], 6, tmp_key); - PrintAndLogEx(SUCCESS, "Found valid key: sector:%3d key type:%c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -1983,7 +1983,50 @@ noValidKeyFound: // Clear the last found key num_to_bytes(0, 6, tmp_key); + if (current_key_type_i == 1) { + if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { + PrintAndLogEx(INFO, "Reading B key: sector: %3d", current_sector_i); + uint8_t sectrail = (FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1); + + mf_readblock_t payload; + payload.blockno = sectrail; + payload.keytype = 0; + + num_to_bytes(e_sector[current_sector_i].Key[0], 6, payload.key); // KEY A + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) goto skipReadBKey; + + if (resp.status != PM3_SUCCESS) goto skipReadBKey; + + uint8_t *data = resp.data.asBytes; + key64 = bytes_to_num(data + 10, 6); + if (verbose){ + num_to_bytes(key64, 6, tmp_key); + PrintAndLogEx(INFO, "Discovered key: sector: %3d key type: %c key: " _YELLOW_("%s"), + current_sector_i, + current_key_type_i ? 'B' : 'A', + sprint_hex(tmp_key, sizeof(tmp_key)) + ); + } + if (key64) { + e_sector[current_sector_i].foundKey[current_key_type_i] = 7; + e_sector[current_sector_i].Key[current_key_type_i] = key64; + num_to_bytes(key64, 6, tmp_key); + PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + current_sector_i, + current_key_type_i ? 'B' : 'A', + sprint_hex(tmp_key, sizeof(tmp_key)) + ); + } + } + } + // Use the nested / hardnested attack +skipReadBKey: if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) { if (prng_type && (! nested_failed)) { uint8_t retries = 0; @@ -2082,6 +2125,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack PrintAndLogEx(INFO, " 4: Reused"); PrintAndLogEx(INFO, " 5: Nested"); PrintAndLogEx(INFO, " 6: Hardnested"); + PrintAndLogEx(INFO, " 7: Read B key with A key"); } PrintAndLogEx(INFO, "\nSaving keys"); diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index 72c1fe78e..296dcdf82 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -401,11 +401,11 @@ static const struct emv_tag emv_tags[] = { { 0xdf811b, "Kernel Configuration", EMV_TAG_GENERIC, NULL }, { 0xdf811c, "Max Lifetime of Torn Transaction Log Record", EMV_TAG_GENERIC, NULL }, { 0xdf811d, "Max Number of Torn Transaction Log Records", EMV_TAG_GENERIC, NULL }, - { 0xdf811e, "Mag-stripe CVM Capability – CVM Required", EMV_TAG_GENERIC, NULL }, + { 0xdf811e, "Mag-stripe CVM Capability - CVM Required", EMV_TAG_GENERIC, NULL }, { 0xdf811f, "Security Capability", EMV_TAG_GENERIC, NULL }, - { 0xdf8120, "Terminal Action Code – Default", EMV_TAG_GENERIC, NULL }, - { 0xdf8121, "Terminal Action Code – Denial", EMV_TAG_GENERIC, NULL }, - { 0xdf8122, "Terminal Action Code – Online", EMV_TAG_GENERIC, NULL }, + { 0xdf8120, "Terminal Action Code - Default", EMV_TAG_GENERIC, NULL }, + { 0xdf8121, "Terminal Action Code - Denial", EMV_TAG_GENERIC, NULL }, + { 0xdf8122, "Terminal Action Code - Online", EMV_TAG_GENERIC, NULL }, { 0xdf8123, "Reader Contactless Floor Limit", EMV_TAG_GENERIC, NULL }, { 0xdf8124, "Reader Contactless Transaction Limit (No On-device CVM)", EMV_TAG_GENERIC, NULL }, { 0xdf8125, "Reader Contactless Transaction Limit (On-device CVM)", EMV_TAG_GENERIC, NULL }, @@ -415,7 +415,7 @@ static const struct emv_tag emv_tags[] = { { 0xdf8129, "Outcome Parameter Set", EMV_TAG_GENERIC, NULL }, { 0xdf812a, "DD Card (Track1)", EMV_TAG_GENERIC, NULL }, { 0xdf812b, "DD Card (Track2)", EMV_TAG_GENERIC, NULL }, - { 0xdf812c, "Mag-stripe CVM Capability – No CVM Required", EMV_TAG_GENERIC, NULL }, + { 0xdf812c, "Mag-stripe CVM Capability - No CVM Required", EMV_TAG_GENERIC, NULL }, { 0xdf812d, "Message Hold Time", EMV_TAG_GENERIC, NULL }, { 0xff8101, "Torn Record", EMV_TAG_GENERIC, NULL }, diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 931f0c845..13f686b51 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -226,8 +226,8 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { reverse_arraybytes(dest, sizeof(dest)); memcpy(mac, dest, 4); //free(cc_nr); - return; } + void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]) { uint8_t *address_data; uint8_t div_key[8]; @@ -245,7 +245,6 @@ void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_ke reverse_arraybytes(dest, sizeof(dest)); memcpy(mac, dest, 4); free(address_data); - return; } #ifndef ON_DEVICE @@ -267,8 +266,8 @@ int testMAC() { PrintAndLogEx(FAILED, "FAILED: MAC calculation failed:"); printarr(" Calculated_MAC", calculated_mac, 4); printarr(" Correct_MAC ", correct_MAC, 4); - return 1; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } #endif diff --git a/client/loclass/cipher.h b/client/loclass/cipher.h index b79dc47cd..7b1257aa5 100644 --- a/client/loclass/cipher.h +++ b/client/loclass/cipher.h @@ -39,6 +39,7 @@ #ifndef CIPHER_H #define CIPHER_H #include +#include "pm3_cmd.h" void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]); void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]); diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index ee440fb73..b50268697 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -127,18 +127,21 @@ uint64_t x_bytes_to_num(uint8_t *src, size_t len) { } return num; } + uint8_t reversebytes(uint8_t b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; b = (b & 0xAA) >> 1 | (b & 0x55) << 1; return b; } + void reverse_arraybytes(uint8_t *arr, size_t len) { uint8_t i; for (i = 0; i < len ; i++) { arr[i] = reversebytes(arr[i]); } } + void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) { uint8_t i; for (i = 0; i < len ; i++) { @@ -202,9 +205,9 @@ static int testBitStream() { for (i = 0 ; i < ARRAYLEN(input) ; i++) { PrintAndLogEx(NORMAL, " IN %02x, OUT %02x", input[i], output[i]); } - return 1; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } static int testReversedBitstream() { @@ -232,9 +235,9 @@ static int testReversedBitstream() { for (i = 0 ; i < ARRAYLEN(input) ; i++) { PrintAndLogEx(NORMAL, " IN %02x, MIDDLE: %02x, OUT %02x", input[i], reverse[i], output[i]); } - return 1; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } diff --git a/client/loclass/cipherutils.h b/client/loclass/cipherutils.h index 70438d33b..6c90326a6 100644 --- a/client/loclass/cipherutils.h +++ b/client/loclass/cipherutils.h @@ -41,6 +41,7 @@ #include #include #include +#include "pm3_cmd.h" typedef struct { uint8_t *buffer;