mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-27 10:34:08 +08:00
fixed checks where the decoded crypto stream compared, added hard coded default keys check, seperate old vs ev1 recovery, simplified thread loops.\nall samples works as expected again.
This commit is contained in:
parent
4ca3f2c3b6
commit
a361118279
2 changed files with 277 additions and 120 deletions
|
@ -108,7 +108,7 @@ This one uses the encrypted tagnonce `nt`=`5a920d85` and the encrypted cmd `3e70
|
||||||
```
|
```
|
||||||
Full output:
|
Full output:
|
||||||
```
|
```
|
||||||
$ ./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a
|
./mf_nonce_brute 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a
|
||||||
Mifare classic nested auth key recovery. Phase 1.
|
Mifare classic nested auth key recovery. Phase 1.
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
uid: 9c599b32
|
uid: 9c599b32
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define _CYAN_(s) "\x1b[36m" s AEND
|
#define _CYAN_(s) "\x1b[36m" s AEND
|
||||||
|
|
||||||
#define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
|
#define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
|
||||||
|
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
// a global mutex to prevent interlaced printing from different threads
|
// a global mutex to prevent interlaced printing from different threads
|
||||||
pthread_mutex_t print_lock;
|
pthread_mutex_t print_lock;
|
||||||
|
@ -68,6 +69,66 @@ uint8_t cmds[8][2] = {
|
||||||
{MIFARE_CMD_TRANSFER, 0}
|
{MIFARE_CMD_TRANSFER, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint64_t g_mifare_default_keys[] = {
|
||||||
|
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||||
|
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||||
|
0xd3f7d3f7d3f7, // NDEF public key
|
||||||
|
0x4b791bea7bcc, // MFC EV1 Signature 17 B
|
||||||
|
0x5C8FF9990DA2, // MFC EV1 Signature 16 A
|
||||||
|
0xD01AFEEB890A, // MFC EV1 Signature 16 B
|
||||||
|
0x75CCB59C9BED, // MFC EV1 Signature 17 A
|
||||||
|
0xfc00018778f7, // Public Transport
|
||||||
|
0x6471a5ef2d1a, // SimonsVoss
|
||||||
|
0x4E3552426B32, // ID06
|
||||||
|
0x6A1987C40A21, // Salto
|
||||||
|
0xef1232ab18a0, // Schlage
|
||||||
|
0x3B7E4FD575AD, //
|
||||||
|
0xb7bf0c13066e, // Gallagher
|
||||||
|
0x135b88a94b8b, // Saflok
|
||||||
|
0x2A2C13CC242A, // Dorma Kaba
|
||||||
|
0x5a7a52d5e20d, // Bosch
|
||||||
|
0x314B49474956, // VIGIK1 A
|
||||||
|
0x564c505f4d41, // VIGIK1 B
|
||||||
|
0x021209197591, // BTCINO
|
||||||
|
0x484558414354, // Intratone
|
||||||
|
0xEC0A9B1A9E06, // Vingcard
|
||||||
|
0x66b31e64ca4b, // Vingcard
|
||||||
|
0x97F5DA640B18, // Bangkok metro key
|
||||||
|
0xA8844B0BCA06, // Metro Valencia key
|
||||||
|
0xE4410EF8ED2D, // Armenian metro
|
||||||
|
0x857464D3AAD1, // HTC Eindhoven key
|
||||||
|
0x08B386463229, // troika
|
||||||
|
0xe00000000000, // icopy
|
||||||
|
0x199404281970, // NSP A
|
||||||
|
0x199404281998, // NSP B
|
||||||
|
0x6A1987C40A21, // SALTO
|
||||||
|
0x7F33625BC129, // SALTO
|
||||||
|
0x484944204953, // HID
|
||||||
|
0x204752454154, // HID
|
||||||
|
0x3B7E4FD575AD, // HID
|
||||||
|
0x11496F97752A, // HID
|
||||||
|
0x3E65E4FB65B3, // Gym
|
||||||
|
0x000000000000, // Blank key
|
||||||
|
0xb0b1b2b3b4b5,
|
||||||
|
0xaabbccddeeff,
|
||||||
|
0x1a2b3c4d5e6f,
|
||||||
|
0x123456789abc,
|
||||||
|
0x010203040506,
|
||||||
|
0x123456abcdef,
|
||||||
|
0xabcdef123456,
|
||||||
|
0x4d3a99c351dd,
|
||||||
|
0x1a982c7e459a,
|
||||||
|
0x714c5c886e97,
|
||||||
|
0x587ee5f9350f,
|
||||||
|
0xa0478cc39091,
|
||||||
|
0x533cb6c723f6,
|
||||||
|
0x8fd0a4f256e9,
|
||||||
|
0x0000014b5c31,
|
||||||
|
0xb578f38a5c61,
|
||||||
|
0x96a301bce267,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//static int global_counter = 0;
|
//static int global_counter = 0;
|
||||||
static int global_found = 0;
|
static int global_found = 0;
|
||||||
static int global_found_candidate = 0;
|
static int global_found_candidate = 0;
|
||||||
|
@ -202,9 +263,10 @@ static uint16_t parity_from_err(uint32_t data, uint16_t par_err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t xored_bits(uint16_t nt_par, uint32_t ntenc, uint16_t ar_par, uint32_t arenc, uint16_t at_par, uint32_t atenc) {
|
static uint16_t xored_bits(uint16_t nt_par, uint32_t ntenc, uint16_t ar_par, uint32_t arenc, uint16_t at_par, uint32_t atenc) {
|
||||||
uint16_t xored = 0;
|
|
||||||
|
|
||||||
|
uint16_t xored = 0;
|
||||||
uint8_t par;
|
uint8_t par;
|
||||||
|
|
||||||
//1st (1st nt)
|
//1st (1st nt)
|
||||||
par = (nt_par >> 12) & 1;
|
par = (nt_par >> 12) & 1;
|
||||||
xored |= par ^ ((ntenc >> 16) & 1);
|
xored |= par ^ ((ntenc >> 16) & 1);
|
||||||
|
@ -258,63 +320,73 @@ static uint16_t xored_bits(uint16_t nt_par, uint32_t ntenc, uint16_t ar_par, uin
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool candidate_nonce(uint32_t xored, uint32_t nt, bool ev1) {
|
static bool candidate_nonce(uint32_t xored, uint32_t nt, bool ev1) {
|
||||||
uint8_t byte, check;
|
uint8_t byte;
|
||||||
|
|
||||||
if (!ev1) {
|
if (!ev1) {
|
||||||
//1st (1st nt)
|
// 1st (1st nt)
|
||||||
byte = (nt >> 24) & 0xFF;
|
byte = (nt >> 24) & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((nt >> 16) & 1) ^ ((xored >> 9) & 1);
|
if (odd_parity(byte) ^ ((nt >> 16) & 1) ^ ((xored >> 9) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//2nd (2nd nt)
|
// 2nd (2nd nt)
|
||||||
byte = (nt >> 16) & 0xFF;
|
byte = (nt >> 16) & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((nt >> 8) & 1) ^ ((xored >> 8) & 1);
|
if (odd_parity(byte) ^ ((nt >> 8) & 1) ^ ((xored >> 8) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//3rd (3rd nt)
|
// 3rd (3rd nt)
|
||||||
byte = (nt >> 8) & 0xFF;
|
byte = (nt >> 8) & 0xFF;
|
||||||
check = odd_parity(byte) ^ (nt & 1) ^ ((xored >> 7) & 1);
|
if (odd_parity(byte) ^ (nt & 1) ^ ((xored >> 7) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ar = prng_successor(nt, 64);
|
uint32_t ar = prng_successor(nt, 64);
|
||||||
|
|
||||||
//4th (1st ar)
|
// 4th (1st ar)
|
||||||
byte = (ar >> 24) & 0xFF;
|
byte = (ar >> 24) & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((ar >> 16) & 1) ^ ((xored >> 6) & 1);
|
if (odd_parity(byte) ^ ((ar >> 16) & 1) ^ ((xored >> 6) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//5th (2nd ar)
|
// 5th (2nd ar)
|
||||||
byte = (ar >> 16) & 0x0FF;
|
byte = (ar >> 16) & 0x0FF;
|
||||||
check = odd_parity(byte) ^ ((ar >> 8) & 1) ^ ((xored >> 5) & 1);
|
if (odd_parity(byte) ^ ((ar >> 8) & 1) ^ ((xored >> 5) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//6th (3rd ar)
|
// 6th (3rd ar)
|
||||||
byte = (ar >> 8) & 0xFF;
|
byte = (ar >> 8) & 0xFF;
|
||||||
check = odd_parity(byte) ^ (ar & 1) ^ ((xored >> 4) & 1);
|
if (odd_parity(byte) ^ (ar & 1) ^ ((xored >> 4) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t at = prng_successor(nt, 96);
|
uint32_t at = prng_successor(nt, 96);
|
||||||
|
|
||||||
//7th (4th ar)
|
// 7th (4th ar)
|
||||||
byte = ar & 0xFF;
|
byte = ar & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((at >> 24) & 1) ^ ((xored >> 3) & 1);
|
if (odd_parity(byte) ^ ((at >> 24) & 1) ^ ((xored >> 3) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//8th (1st at)
|
// 8th (1st at)
|
||||||
byte = (at >> 24) & 0xFF;
|
byte = (at >> 24) & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((at >> 16) & 1) ^ ((xored >> 2) & 1);
|
if (odd_parity(byte) ^ ((at >> 16) & 1) ^ ((xored >> 2) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//9th (2nd at)
|
// 9th (2nd at)
|
||||||
byte = (at >> 16) & 0xFF;
|
byte = (at >> 16) & 0xFF;
|
||||||
check = odd_parity(byte) ^ ((at >> 8) & 1) ^ ((xored >> 1) & 1) ;
|
if (odd_parity(byte) ^ ((at >> 8) & 1) ^ ((xored >> 1) & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//10th (3rd at)
|
// 10th (3rd at)
|
||||||
byte = (at >> 8) & 0xFF;
|
byte = (at >> 8) & 0xFF;
|
||||||
check = odd_parity(byte) ^ (at & 1) ^ (xored & 1);
|
if (odd_parity(byte) ^ (at & 1) ^ (xored & 1)) {
|
||||||
if (check) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -322,27 +394,34 @@ static bool candidate_nonce(uint32_t xored, uint32_t nt, bool ev1) {
|
||||||
static bool checkValidCmd(uint32_t decrypted) {
|
static bool checkValidCmd(uint32_t decrypted) {
|
||||||
uint8_t cmd = (decrypted >> 24) & 0xFF;
|
uint8_t cmd = (decrypted >> 24) & 0xFF;
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
if (cmd == cmds[i][0])
|
if (cmd == cmds[i][0]) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) {
|
static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) {
|
||||||
|
// if we don't have enough data then this might be a false positive
|
||||||
|
|
||||||
bool ok = false;
|
if (cmd == NULL) {
|
||||||
if (cmd == NULL)
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
if (cmd[0] == cmds[i][0]) {
|
if (cmd[0] == cmds[i][0]) {
|
||||||
|
|
||||||
if (n >= 4)
|
int res = 0;
|
||||||
ok = CheckCrc14443(CRC_14443_A, cmd, 4);
|
|
||||||
|
|
||||||
if (cmds[i][1] > 0 && n >= cmds[i][1])
|
if (n >= 4) {
|
||||||
ok = CheckCrc14443(CRC_14443_A, cmd + 4, cmds[i][1]);
|
res = CheckCrc14443(CRC_14443_A, cmd, 4);
|
||||||
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (res == 0 && cmds[i][1] > 0 && n >= cmds[i][1]) {
|
||||||
|
res = CheckCrc14443(CRC_14443_A, cmd, cmds[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,9 +439,60 @@ static bool checkCRC(uint32_t decrypted) {
|
||||||
return CheckCrc14443(CRC_14443_A, data, sizeof(data));
|
return CheckCrc14443(CRC_14443_A, data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *check_default_keys(void *arguments) {
|
||||||
|
struct thread_key_args *args = (struct thread_key_args *) arguments;
|
||||||
|
uint8_t local_enc[args->enc_len];
|
||||||
|
memcpy(local_enc, args->enc, args->enc_len);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < ARRAYLEN(g_mifare_default_keys); i++) {
|
||||||
|
|
||||||
|
uint64_t key = g_mifare_default_keys[i];
|
||||||
|
if (args->part_key != (key & 0xffffffff)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init cipher with key
|
||||||
|
struct Crypto1State *pcs = crypto1_create(key);
|
||||||
|
|
||||||
|
// NESTED decrypt nt with help of new key
|
||||||
|
crypto1_word(pcs, args->nt_enc ^ args->uid, 0);
|
||||||
|
crypto1_word(pcs, args->nr_enc, 1);
|
||||||
|
crypto1_word(pcs, 0, 0);
|
||||||
|
crypto1_word(pcs, 0, 0);
|
||||||
|
|
||||||
|
// decrypt bytes
|
||||||
|
uint8_t dec[args->enc_len];
|
||||||
|
for (int j = 0; j < args->enc_len; j++) {
|
||||||
|
dec[j] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[j];
|
||||||
|
}
|
||||||
|
crypto1_destroy(pcs);
|
||||||
|
|
||||||
|
// check if cmd exists
|
||||||
|
bool res = checkValidCmdByte(dec, args->enc_len);
|
||||||
|
if (args->enc_len > 4) {
|
||||||
|
res |= checkValidCmdByte(dec + 4, args->enc_len -4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
__sync_fetch_and_add(&global_found, 1);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&print_lock);
|
||||||
|
printf("\nFound a default key!\n");
|
||||||
|
printf("enc: %s\n", sprint_hex_inrow_ex(local_enc, args->enc_len, 0));
|
||||||
|
printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0));
|
||||||
|
printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key);
|
||||||
|
pthread_mutex_unlock(&print_lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(args);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void *brute_thread(void *arguments) {
|
static void *brute_thread(void *arguments) {
|
||||||
|
|
||||||
//int shift = (int)arg;
|
|
||||||
struct thread_args *args = (struct thread_args *) arguments;
|
struct thread_args *args = (struct thread_args *) arguments;
|
||||||
|
|
||||||
struct Crypto1State *revstate = NULL;
|
struct Crypto1State *revstate = NULL;
|
||||||
|
@ -373,11 +503,10 @@ static void *brute_thread(void *arguments) {
|
||||||
uint32_t nt; // current tag nonce
|
uint32_t nt; // current tag nonce
|
||||||
|
|
||||||
uint32_t p64 = 0;
|
uint32_t p64 = 0;
|
||||||
uint32_t count;
|
|
||||||
// TC == 4 (
|
// TC == 4 (
|
||||||
// threads calls 0 ev1 == false
|
// threads calls 0 ev1 == false
|
||||||
// threads calls 0,1,2 ev1 == true
|
// threads calls 0,1,2 ev1 == true
|
||||||
for (count = args->idx; count <= 0xFFFF; count += thread_count - 1) {
|
for (uint32_t count = args->idx; count <= 0xFFFF; count += thread_count) {
|
||||||
|
|
||||||
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
|
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
|
||||||
break;
|
break;
|
||||||
|
@ -385,8 +514,9 @@ static void *brute_thread(void *arguments) {
|
||||||
|
|
||||||
nt = count << 16 | prng_successor(count, 16);
|
nt = count << 16 | prng_successor(count, 16);
|
||||||
|
|
||||||
if (candidate_nonce(args->xored, nt, args->ev1) == false)
|
if (candidate_nonce(args->xored, nt, args->ev1) == false) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
p64 = prng_successor(nt, 64);
|
p64 = prng_successor(nt, 64);
|
||||||
ks2 = ar_enc ^ p64;
|
ks2 = ar_enc ^ p64;
|
||||||
|
@ -394,12 +524,16 @@ static void *brute_thread(void *arguments) {
|
||||||
revstate = lfsr_recovery64(ks2, ks3);
|
revstate = lfsr_recovery64(ks2, ks3);
|
||||||
ks4 = crypto1_word(revstate, 0, 0);
|
ks4 = crypto1_word(revstate, 0, 0);
|
||||||
|
|
||||||
if (ks4 != 0) {
|
if (ks4 == 0) {
|
||||||
|
free(revstate);
|
||||||
// lock this section to avoid interlacing prints from different threats
|
continue;
|
||||||
pthread_mutex_lock(&print_lock);
|
}
|
||||||
if (args->ev1)
|
|
||||||
printf("\n**** Possible key candidate ****\n");
|
// lock this section to avoid interlacing prints from different threats
|
||||||
|
pthread_mutex_lock(&print_lock);
|
||||||
|
if (args->ev1) {
|
||||||
|
printf("\n---> " _YELLOW_(" Possible key candidate")" <---\n");
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf("thread #%d idx %d %s\n", args->thread, args->idx, (args->ev1) ? "(Ev1)" : "");
|
printf("thread #%d idx %d %s\n", args->thread, args->idx, (args->ev1) ? "(Ev1)" : "");
|
||||||
|
@ -408,54 +542,53 @@ static void *brute_thread(void *arguments) {
|
||||||
printf("ks3:%08x\n", ks3);
|
printf("ks3:%08x\n", ks3);
|
||||||
printf("ks4:%08x\n", ks4);
|
printf("ks4:%08x\n", ks4);
|
||||||
#endif
|
#endif
|
||||||
if (cmd_enc) {
|
if (cmd_enc) {
|
||||||
uint32_t decrypted = ks4 ^ cmd_enc;
|
uint32_t decrypted = ks4 ^ cmd_enc;
|
||||||
printf("CMD enc( %08x )\n", cmd_enc);
|
printf("CMD enc( %08x )\n", cmd_enc);
|
||||||
printf(" dec( %08x ) ", decrypted);
|
printf(" dec( %08x ) ", decrypted);
|
||||||
|
|
||||||
// check if cmd exists
|
// check if cmd exists
|
||||||
uint8_t isOK = checkValidCmd(decrypted);
|
uint8_t isOK = checkValidCmd(decrypted);
|
||||||
if (isOK == false) {
|
if (isOK == false) {
|
||||||
printf(_RED_("<-- not a valid cmd\n"));
|
printf(_RED_("<-- not a valid cmd\n"));
|
||||||
pthread_mutex_unlock(&print_lock);
|
pthread_mutex_unlock(&print_lock);
|
||||||
free(revstate);
|
free(revstate);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Add a crc-check.
|
|
||||||
isOK = checkCRC(decrypted);
|
|
||||||
if (isOK == false) {
|
|
||||||
printf(_RED_("<-- not a valid crc\n"));
|
|
||||||
pthread_mutex_unlock(&print_lock);
|
|
||||||
free(revstate);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
printf("<-- valid cmd\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lfsr_rollback_word(revstate, 0, 0);
|
// Add a crc-check.
|
||||||
lfsr_rollback_word(revstate, 0, 0);
|
isOK = checkCRC(decrypted);
|
||||||
lfsr_rollback_word(revstate, 0, 0);
|
if (isOK == false) {
|
||||||
lfsr_rollback_word(revstate, nr_enc, 1);
|
printf(_RED_("<-- not a valid crc\n"));
|
||||||
lfsr_rollback_word(revstate, uid ^ nt, 0);
|
pthread_mutex_unlock(&print_lock);
|
||||||
crypto1_get_lfsr(revstate, &key);
|
free(revstate);
|
||||||
|
continue;
|
||||||
if (args->ev1) {
|
|
||||||
// if it was EV1, we know for sure xxxAAAAAAAA recovery
|
|
||||||
printf("\nKey candidate [ " _YELLOW_("....%08" PRIx64)" ]\n\n", key & 0xFFFFFFFF);
|
|
||||||
__sync_fetch_and_add(&global_found_candidate, 1);
|
|
||||||
} else {
|
} else {
|
||||||
printf("\nKey candidate [ " _GREEN_("....%08" PRIx64) " ]\n\n", key & 0xFFFFFFFF);
|
printf("<-- " _GREEN_("valid cmd") "\n");
|
||||||
__sync_fetch_and_add(&global_found, 1);
|
|
||||||
}
|
}
|
||||||
//release lock
|
|
||||||
pthread_mutex_unlock(&print_lock);
|
|
||||||
__sync_fetch_and_add(&global_candidate_key, key);
|
|
||||||
free(revstate);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lfsr_rollback_word(revstate, 0, 0);
|
||||||
|
lfsr_rollback_word(revstate, 0, 0);
|
||||||
|
lfsr_rollback_word(revstate, 0, 0);
|
||||||
|
lfsr_rollback_word(revstate, nr_enc, 1);
|
||||||
|
lfsr_rollback_word(revstate, uid ^ nt, 0);
|
||||||
|
crypto1_get_lfsr(revstate, &key);
|
||||||
free(revstate);
|
free(revstate);
|
||||||
|
|
||||||
|
if (args->ev1) {
|
||||||
|
// if it was EV1, we know for sure xxxAAAAAAAA recovery
|
||||||
|
printf("\nKey candidate [ " _YELLOW_("....%08" PRIx64)" ]\n\n", key & 0xFFFFFFFF);
|
||||||
|
__sync_fetch_and_add(&global_found_candidate, 1);
|
||||||
|
} else {
|
||||||
|
printf("\nKey candidate [ " _GREEN_("....%08" PRIx64) " ]", key & 0xFFFFFFFF);
|
||||||
|
printf("\nKey candidate [ " _GREEN_("%12" PRIx64) " ]\n\n", key);
|
||||||
|
__sync_fetch_and_add(&global_found, 1);
|
||||||
|
}
|
||||||
|
// release lock
|
||||||
|
pthread_mutex_unlock(&print_lock);
|
||||||
|
__sync_fetch_and_add(&global_candidate_key, key);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
free(args);
|
free(args);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -487,8 +620,9 @@ static void *brute_key_thread(void *arguments) {
|
||||||
|
|
||||||
// decrypt 22 bytes
|
// decrypt 22 bytes
|
||||||
uint8_t dec[args->enc_len];
|
uint8_t dec[args->enc_len];
|
||||||
for (int i = 0; i < args->enc_len; i++)
|
for (int i = 0; i < args->enc_len; i++) {
|
||||||
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
|
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
|
||||||
|
}
|
||||||
|
|
||||||
crypto1_destroy(pcs);
|
crypto1_destroy(pcs);
|
||||||
|
|
||||||
|
@ -496,6 +630,7 @@ static void *brute_key_thread(void *arguments) {
|
||||||
if (checkValidCmdByte(dec, args->enc_len) == false) {
|
if (checkValidCmdByte(dec, args->enc_len) == false) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
__sync_fetch_and_add(&global_found, 1);
|
__sync_fetch_and_add(&global_found, 1);
|
||||||
|
|
||||||
// lock this section to avoid interlacing prints from different threats
|
// lock this section to avoid interlacing prints from different threats
|
||||||
|
@ -547,15 +682,15 @@ int main(int argc, const char *argv[]) {
|
||||||
sscanf(argv[7], "%x", &at_enc);
|
sscanf(argv[7], "%x", &at_enc);
|
||||||
sscanf(argv[8], "%x", &at_par_err);
|
sscanf(argv[8], "%x", &at_par_err);
|
||||||
|
|
||||||
|
// next encrypted command + a full read/write
|
||||||
int enc_len = 0;
|
int enc_len = 0;
|
||||||
uint8_t enc[ENC_LEN] = {0}; // next encrypted command + a full read/write
|
uint8_t enc[ENC_LEN] = {0};
|
||||||
if (argc > 9) {
|
if (argc > 9) {
|
||||||
// sscanf(argv[9], "%x", &cmd_enc);
|
|
||||||
param_gethex_to_eol(argv[9], 0, enc, sizeof(enc), &enc_len);
|
param_gethex_to_eol(argv[9], 0, enc, sizeof(enc), &enc_len);
|
||||||
cmd_enc = (enc[0] << 24 | enc[1] << 16 | enc[2] << 8 | enc[3]);
|
cmd_enc = (enc[0] << 24 | enc[1] << 16 | enc[2] << 8 | enc[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("----------- " _CYAN_("Phase 1") " ------------------------\n");
|
printf("----------- " _CYAN_("Phase 1 examine") " ------------------------\n");
|
||||||
printf("uid.................. %08x\n", uid);
|
printf("uid.................. %08x\n", uid);
|
||||||
printf("nt encrypted......... %08x\n", nt_enc);
|
printf("nt encrypted......... %08x\n", nt_enc);
|
||||||
printf("nt parity err........ %04x\n", nt_par_err);
|
printf("nt parity err........ %04x\n", nt_par_err);
|
||||||
|
@ -574,7 +709,7 @@ int main(int argc, const char *argv[]) {
|
||||||
uint16_t ar_par = parity_from_err(ar_enc, ar_par_err);
|
uint16_t ar_par = parity_from_err(ar_enc, ar_par_err);
|
||||||
uint16_t at_par = parity_from_err(at_enc, at_par_err);
|
uint16_t at_par = parity_from_err(at_enc, at_par_err);
|
||||||
|
|
||||||
//calc (parity XOR corresponding nonce bit encoded with the same keystream bit)
|
// calc (parity XOR corresponding nonce bit encoded with the same keystream bit)
|
||||||
uint16_t xored = xored_bits(nt_par, nt_enc, ar_par, ar_enc, at_par, at_enc);
|
uint16_t xored = xored_bits(nt_par, nt_enc, ar_par, ar_enc, at_par, at_enc);
|
||||||
|
|
||||||
#if !defined(_WIN32) || !defined(__WIN32__)
|
#if !defined(_WIN32) || !defined(__WIN32__)
|
||||||
|
@ -586,40 +721,58 @@ int main(int argc, const char *argv[]) {
|
||||||
printf("\nBruteforce using " _YELLOW_("%d") " threads\n", thread_count);
|
printf("\nBruteforce using " _YELLOW_("%d") " threads\n", thread_count);
|
||||||
printf("looking for the last bytes of the encrypted tagnonce\n");
|
printf("looking for the last bytes of the encrypted tagnonce\n");
|
||||||
|
|
||||||
|
printf("\nTarget old MFC...\n");
|
||||||
|
|
||||||
pthread_t threads[thread_count];
|
pthread_t threads[thread_count];
|
||||||
|
|
||||||
// create a mutex to avoid interlacing print commands from our different threads
|
// create a mutex to avoid interlacing print commands from our different threads
|
||||||
pthread_mutex_init(&print_lock, NULL);
|
pthread_mutex_init(&print_lock, NULL);
|
||||||
|
|
||||||
// one thread T0 for none EV1.
|
|
||||||
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
|
||||||
a->xored = xored;
|
|
||||||
a->thread = 0;
|
|
||||||
a->idx = 0;
|
|
||||||
a->ev1 = false;
|
|
||||||
pthread_create(&threads[0], NULL, brute_thread, (void *)a);
|
|
||||||
|
|
||||||
// the rest of available threads to EV1 scenario
|
// the rest of available threads to EV1 scenario
|
||||||
for (int i = 0; i < thread_count - 1; ++i) {
|
for (int i = 0; i < thread_count; ++i) {
|
||||||
struct thread_args *b = calloc(1, sizeof(struct thread_args));
|
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||||
b->xored = xored;
|
a->xored = xored;
|
||||||
b->thread = i + 1;
|
a->thread = i;
|
||||||
b->idx = i;
|
a->idx = i;
|
||||||
b->ev1 = true;
|
a->ev1 = false;
|
||||||
pthread_create(&threads[i + 1], NULL, brute_thread, (void *)b);
|
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for threads to terminate:
|
// wait for threads to terminate:
|
||||||
for (int i = 0; i < thread_count; ++i)
|
for (int i = 0; i < thread_count; ++i) {
|
||||||
pthread_join(threads[i], NULL);
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
t1 = msclock() - t1;
|
t1 = msclock() - t1;
|
||||||
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||||
|
|
||||||
|
|
||||||
if (!global_found && !global_found_candidate) {
|
if (!global_found && !global_found_candidate) {
|
||||||
printf("\nFailed to find a key\n\n");
|
printf("\nTarget MFC Ev1...\n");
|
||||||
goto out;
|
|
||||||
|
t1 = msclock();
|
||||||
|
// the rest of available threads to EV1 scenario
|
||||||
|
for (int i = 0; i < thread_count; ++i) {
|
||||||
|
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||||
|
a->xored = xored;
|
||||||
|
a->thread = i;
|
||||||
|
a->idx = i;
|
||||||
|
a->ev1 = true;
|
||||||
|
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for threads to terminate:
|
||||||
|
for (int i = 0; i < thread_count; ++i) {
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
t1 = msclock() - t1;
|
||||||
|
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||||
|
|
||||||
|
|
||||||
|
if (!global_found && !global_found_candidate) {
|
||||||
|
printf("\nFailed to find a key\n\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc_len < 4) {
|
if (enc_len < 4) {
|
||||||
|
@ -631,13 +784,13 @@ int main(int argc, const char *argv[]) {
|
||||||
global_found = 0;
|
global_found = 0;
|
||||||
global_found_candidate = 0;
|
global_found_candidate = 0;
|
||||||
|
|
||||||
printf("\n----------- " _CYAN_("Phase 2") " ------------------------\n");
|
printf("\n----------- " _CYAN_("Phase 2 validating") " ------------------------\n");
|
||||||
printf("uid.................. %08x\n", uid);
|
printf("uid.................. %08x\n", uid);
|
||||||
printf("partial key.......... %08x\n", (uint32_t)(global_candidate_key & 0xFFFFFFFF));
|
printf("partial key.......... %08x\n", (uint32_t)(global_candidate_key & 0xFFFFFFFF));
|
||||||
printf("nt enc............... %08x\n", nt_enc);
|
printf("nt enc............... %08x\n", nt_enc);
|
||||||
printf("nr enc............... %08x\n", nr_enc);
|
printf("nr enc............... %08x\n", nr_enc);
|
||||||
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len, 0));
|
||||||
printf("\nlooking for the upper 16 bits of key\n");
|
printf("\nLooking for the upper 16 bits of the key\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
// threads
|
// threads
|
||||||
|
@ -651,12 +804,16 @@ int main(int argc, const char *argv[]) {
|
||||||
b->nr_enc = nr_enc;
|
b->nr_enc = nr_enc;
|
||||||
b->enc_len = enc_len;
|
b->enc_len = enc_len;
|
||||||
memcpy(b->enc, enc, enc_len);
|
memcpy(b->enc, enc, enc_len);
|
||||||
pthread_create(&threads[i], NULL, brute_key_thread, (void *)b);
|
if ( i == 0)
|
||||||
|
pthread_create(&threads[0], NULL, check_default_keys, (void *)b);
|
||||||
|
else
|
||||||
|
pthread_create(&threads[i], NULL, brute_key_thread, (void *)b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for threads to terminate:
|
// wait for threads to terminate:
|
||||||
for (int i = 0; i < thread_count; ++i)
|
for (int i = 0; i < thread_count; ++i) {
|
||||||
pthread_join(threads[i], NULL);
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (!global_found && !global_found_candidate) {
|
if (!global_found && !global_found_candidate) {
|
||||||
printf("\nfailed to find a key\n\n");
|
printf("\nfailed to find a key\n\n");
|
||||||
|
|
Loading…
Reference in a new issue