mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-20 23:36:31 +08:00
part of monstermerge..
This commit is contained in:
parent
6519ae6f88
commit
a8569849d6
|
@ -8,7 +8,6 @@
|
|||
// Analyse bytes commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmdanalyse.h"
|
||||
//#include "nonce2key/nonce2key.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "mifare.h"
|
||||
#include "cmdhfmf.h"
|
||||
#include "cmdhfmfu.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "mifarehost.h"
|
||||
#include "cmdhf.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
|
132
client/cmdhfmf.c
132
client/cmdhfmf.c
|
@ -290,119 +290,30 @@ int usage_hf14_csave(void){
|
|||
}
|
||||
|
||||
int CmdHF14AMifare(const char *Cmd) {
|
||||
uint32_t uid = 0;
|
||||
uint32_t nt = 0, nr = 0;
|
||||
uint64_t par_list = 0, ks_list = 0, r_key = 0;
|
||||
int16_t isOK = 0;
|
||||
int tmpchar;
|
||||
uint8_t blockNo = 0, keytype = MIFARE_AUTH_KEYA;
|
||||
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
|
||||
uint64_t key = 0;
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if ( cmdp == 'H' || cmdp == 'h') return usage_hf14_mifare();
|
||||
|
||||
blockNo = param_get8(Cmd, 0);
|
||||
blockno = param_get8(Cmd, 0);
|
||||
|
||||
cmdp = param_getchar(Cmd, 1);
|
||||
if (cmdp == 'B' || cmdp == 'b')
|
||||
keytype = MIFARE_AUTH_KEYB;
|
||||
|
||||
UsbCommand c = {CMD_READER_MIFARE, {true, blockNo, keytype}};
|
||||
key_type = MIFARE_AUTH_KEYB;
|
||||
|
||||
// message
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
printf("Executing darkside attack. Expected execution time: 25sec on average :-)\n");
|
||||
printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n");
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
clock_t t1 = clock();
|
||||
time_t start, end;
|
||||
time(&start);
|
||||
|
||||
start:
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
//flush queue
|
||||
while (ukbhit()) {
|
||||
tmpchar = getchar();
|
||||
(void)tmpchar;
|
||||
int isOK = mfDarkside(blockno, key_type, &key);
|
||||
switch (isOK) {
|
||||
case -1 : PrintAndLog("Button pressed. Aborted."); return 1;
|
||||
case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)."); return 1;
|
||||
case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable)."); return 1;
|
||||
case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
|
||||
PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour."); return 1;
|
||||
case -5 : PrintAndLog("Aborted via keyboard."); return 1;
|
||||
default : PrintAndLog("Found valid key: %012" PRIx64 "\n", key); break;
|
||||
}
|
||||
|
||||
UsbCommand resp;
|
||||
|
||||
// wait cycle
|
||||
while (true) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
if (ukbhit()) {
|
||||
tmpchar = getchar();
|
||||
(void)tmpchar;
|
||||
printf("\naborted via keyboard!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
isOK = resp.arg[0];
|
||||
printf("\n");
|
||||
uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4);
|
||||
nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4);
|
||||
par_list = bytes_to_num(resp.d.asBytes + 8, 8);
|
||||
ks_list = bytes_to_num(resp.d.asBytes + 16, 8);
|
||||
nr = bytes_to_num(resp.d.asBytes + 24, 4);
|
||||
|
||||
switch (isOK) {
|
||||
case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;
|
||||
case -2 : PrintAndLog("Card isn't vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;
|
||||
case -3 : PrintAndLog("Card isn't vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;
|
||||
case -4 : PrintAndLog("Card isn't vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
|
||||
PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour.\n"); break;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
// error
|
||||
if (isOK != 1) return 1;
|
||||
|
||||
if (par_list == 0 && ks_list != 0) {
|
||||
// this special attack when parities is zero, uses checkkeys. Which now with block/keytype option also needs.
|
||||
// but it uses 0|1 instead of 0x60|0x61...
|
||||
if (nonce2key_ex(blockNo, keytype - 0x60 , uid, nt, nr, ks_list, &r_key) ){
|
||||
PrintAndLog("Trying again with a different reader nonce...");
|
||||
c.arg[0] = false;
|
||||
goto start;
|
||||
} else {
|
||||
PrintAndLog("Found valid key: %012" PRIx64 " \n", r_key);
|
||||
goto END;
|
||||
}
|
||||
}
|
||||
|
||||
// execute original function from util nonce2key
|
||||
if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {
|
||||
isOK = 2;
|
||||
PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);
|
||||
PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce...");
|
||||
c.arg[0] = false;
|
||||
goto start;
|
||||
} else {
|
||||
|
||||
// nonce2key found a candidate key. Lets verify it.
|
||||
uint8_t keyblock[] = {0,0,0,0,0,0};
|
||||
num_to_bytes(r_key, 6, keyblock);
|
||||
uint64_t key64 = 0;
|
||||
int res = mfCheckKeys(blockNo, keytype - 0x60 , false, 1, keyblock, &key64);
|
||||
if ( res > 0 ) {
|
||||
PrintAndLog("Candidate Key found (%012" PRIx64 ") - Test authentication failed. [%d] Restarting darkside attack", r_key, res);
|
||||
goto start;
|
||||
}
|
||||
PrintAndLog("Found valid key: %012" PRIx64 " \n", r_key);
|
||||
}
|
||||
END:
|
||||
t1 = clock() - t1;
|
||||
time(&end);
|
||||
unsigned long elapsed_time = difftime(end, start);
|
||||
if ( t1 > 0 )
|
||||
PrintAndLog("Time in darkside: %.0f ticks %u seconds\n", (float)t1, elapsed_time);
|
||||
PrintAndLog("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -926,7 +837,7 @@ int CmdHF14AMfNested(const char *Cmd) {
|
|||
switch (isOK) {
|
||||
case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
|
||||
case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;
|
||||
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random number generator is not predictable).\n"); break;
|
||||
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break;
|
||||
case -4 : PrintAndLog("No valid key found"); break;
|
||||
case -5 :
|
||||
key64 = bytes_to_num(keyBlock, 6);
|
||||
|
@ -978,7 +889,7 @@ int CmdHF14AMfNested(const char *Cmd) {
|
|||
|
||||
if (!res) {
|
||||
e_sector[i].Key[j] = key64;
|
||||
e_sector[i].foundKey[j] = TRUE;
|
||||
e_sector[i].foundKey[j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1004,7 +915,7 @@ int CmdHF14AMfNested(const char *Cmd) {
|
|||
switch (isOK) {
|
||||
case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break;
|
||||
case -2 : PrintAndLog("Button pressed. Aborted.\n"); break;
|
||||
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (its random number generator is not predictable).\n"); break;
|
||||
case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break;
|
||||
case -4 : //key not found
|
||||
calibrate = false;
|
||||
iterations++;
|
||||
|
@ -1131,6 +1042,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
bool slow = false;
|
||||
int tests = 0;
|
||||
|
||||
|
||||
if (ctmp == 'R' || ctmp == 'r') {
|
||||
nonce_file_read = true;
|
||||
if (!param_gethex(Cmd, 1, trgkey, 12)) {
|
||||
|
@ -1138,6 +1050,9 @@ int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
}
|
||||
} else if (ctmp == 'T' || ctmp == 't') {
|
||||
tests = param_get32ex(Cmd, 1, 100, 10);
|
||||
if (!param_gethex(Cmd, 2, trgkey, 12)) {
|
||||
know_target_key = true;
|
||||
}
|
||||
} else {
|
||||
blockNo = param_get8(Cmd, 0);
|
||||
ctmp = param_getchar(Cmd, 1);
|
||||
|
@ -1193,8 +1108,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
slow ? "Yes" : "No",
|
||||
tests);
|
||||
|
||||
uint64_t foundkey = 0;
|
||||
int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, know_target_key ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey);
|
||||
int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, know_target_key?trgkey:NULL, nonce_file_read, nonce_file_write, slow, tests);
|
||||
|
||||
if (isOK) {
|
||||
switch (isOK) {
|
||||
|
@ -1525,7 +1439,7 @@ void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose) {
|
|||
if (k_sector == NULL)
|
||||
emptySectorTable();
|
||||
|
||||
success = tryMfk32_moebius(data, &key, verbose);
|
||||
success = mfkey32_moebius(data, &key);
|
||||
if (success) {
|
||||
uint8_t sector = data.sector;
|
||||
uint8_t keytype = data.keytype;
|
||||
|
|
|
@ -23,8 +23,9 @@
|
|||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "mifare.h" // nonces_t struct
|
||||
#include "mfkey.h" // mfkey32_moebious
|
||||
#include "cmdhfmfhard.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "mifarehost.h"
|
||||
|
||||
extern int CmdHFMF(const char *Cmd);
|
||||
|
||||
|
|
3739
client/cmdhfmfhard.c
3739
client/cmdhfmfhard.c
File diff suppressed because it is too large
Load diff
|
@ -11,26 +11,38 @@
|
|||
#ifndef CMDHFMFHARD_H__
|
||||
#define CMDHFMFHARD_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include "proxmark3.h" // time_t , PRIu32
|
||||
#include "sleep.h"
|
||||
#include "cmdmain.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "nonce2key/crapto1.h"
|
||||
#include "nonce2key/crypto1_bs.h"
|
||||
#include "parity.h"
|
||||
// don't include for APPLE/mac which has malloc stuff elsewhere.
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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, int tests, uint64_t *foundkey);
|
||||
#define NUM_SUMS 19 // number of possible sum property values
|
||||
|
||||
typedef struct guess_sum_a8 {
|
||||
float prob;
|
||||
uint64_t num_states;
|
||||
uint8_t sum_a8_idx;
|
||||
} guess_sum_a8_t;
|
||||
|
||||
typedef struct noncelistentry {
|
||||
uint32_t nonce_enc;
|
||||
uint8_t par_enc;
|
||||
void *next;
|
||||
} noncelistentry_t;
|
||||
|
||||
typedef struct noncelist {
|
||||
uint16_t num;
|
||||
uint16_t Sum;
|
||||
guess_sum_a8_t sum_a8_guess[NUM_SUMS];
|
||||
bool sum_a8_guess_dirty;
|
||||
float expected_num_brute_force;
|
||||
uint8_t BitFlips[0x400];
|
||||
uint32_t *states_bitarray[2];
|
||||
uint32_t num_states_bitarray[2];
|
||||
bool all_bitflips_dirty[2];
|
||||
noncelistentry_t *first;
|
||||
} noncelist_t;
|
||||
|
||||
extern 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, int tests);
|
||||
extern void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -7,34 +7,257 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// mifare commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "mifarehost.h"
|
||||
|
||||
// MIFARE
|
||||
extern int compar_int(const void * a, const void * b) {
|
||||
static int compare_uint64(const void *a, const void *b) {
|
||||
// didn't work: (the result is truncated to 32 bits)
|
||||
//return (*(uint64_t*)b - *(uint64_t*)a);
|
||||
//return (*(int64_t*)b - *(int64_t*)a);
|
||||
|
||||
// better:
|
||||
if (*(uint64_t*)b > *(uint64_t*)a) return 1;
|
||||
if (*(uint64_t*)b < *(uint64_t*)a) return -1;
|
||||
return 0;
|
||||
if (*(uint64_t*)b == *(uint64_t*)a) return 0;
|
||||
if (*(uint64_t*)b < *(uint64_t*)a) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//return (*(uint64_t*)b > *(uint64_t*)a) - (*(uint64_t*)b < *(uint64_t*)a);
|
||||
// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned.
|
||||
static uint32_t intersection(uint64_t *list1, uint64_t *list2) {
|
||||
if (list1 == NULL || list2 == NULL)
|
||||
return 0;
|
||||
|
||||
uint64_t *p1, *p2, *p3;
|
||||
p1 = p3 = list1;
|
||||
p2 = list2;
|
||||
|
||||
while ( *p1 != -1 && *p2 != -1 ) {
|
||||
if (compare_uint64(p1, p2) == 0) {
|
||||
*p3++ = *p1++;
|
||||
p2++;
|
||||
}
|
||||
else {
|
||||
while (compare_uint64(p1, p2) < 0) ++p1;
|
||||
while (compare_uint64(p1, p2) > 0) ++p2;
|
||||
}
|
||||
}
|
||||
*p3 = -1;
|
||||
return p3 - list1;
|
||||
}
|
||||
|
||||
// Darkside attack (hf mf mifare)
|
||||
// if successful it will return a list of keys, not just one.
|
||||
static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
|
||||
struct Crypto1State *states;
|
||||
uint32_t i, pos, rr;
|
||||
uint8_t bt, ks3x[8], par[8][8];
|
||||
uint64_t key_recovered;
|
||||
static uint64_t *keylist;
|
||||
rr = 0;
|
||||
|
||||
// Reset the last three significant bits of the reader nonce
|
||||
nr &= 0xffffff1f;
|
||||
|
||||
for ( pos = 0; pos < 8; pos++ ) {
|
||||
ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f;
|
||||
bt = (par_info >> (pos*8)) & 0xff;
|
||||
for ( i = 0; i < 8; i++) {
|
||||
par[7-pos][i] = (bt >> i) & 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
states = lfsr_common_prefix(nr, rr, ks3x, par, (par_info == 0));
|
||||
|
||||
if (!states) {
|
||||
PrintAndLog("Failed getting states");
|
||||
*keys = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
keylist = (uint64_t*)states;
|
||||
|
||||
for (i = 0; keylist[i]; i++) {
|
||||
lfsr_rollback_word(states+i, uid^nt, 0);
|
||||
crypto1_get_lfsr(states+i, &key_recovered);
|
||||
keylist[i] = key_recovered;
|
||||
}
|
||||
keylist[i] = -1;
|
||||
|
||||
*keys = keylist;
|
||||
return i;
|
||||
}
|
||||
|
||||
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key)
|
||||
{
|
||||
uint32_t uid = 0;
|
||||
uint32_t nt = 0, nr = 0;
|
||||
uint64_t par_list = 0, ks_list = 0;
|
||||
uint64_t *keylist = NULL, *last_keylist = NULL;
|
||||
uint32_t keycount = 0;
|
||||
int16_t isOK = 0;
|
||||
|
||||
UsbCommand c = {CMD_READER_MIFARE, {true, blockno, key_type}};
|
||||
|
||||
// message
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
printf("Executing command. Expected execution time: 25sec on average\n");
|
||||
printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n");
|
||||
printf("-------------------------------------------------------------------------\n");
|
||||
|
||||
|
||||
while (true) {
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
//flush queue
|
||||
while (ukbhit()) {
|
||||
int gc = getchar(); (void) gc;
|
||||
}
|
||||
|
||||
// wait cycle
|
||||
while (true) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
if (ukbhit()) {
|
||||
int gc = getchar(); (void) gc;
|
||||
return -5;
|
||||
break;
|
||||
}
|
||||
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
isOK = resp.arg[0];
|
||||
if (isOK < 0)
|
||||
return isOK;
|
||||
|
||||
uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4);
|
||||
nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4);
|
||||
par_list = bytes_to_num(resp.d.asBytes + 8, 8);
|
||||
ks_list = bytes_to_num(resp.d.asBytes + 16, 8);
|
||||
nr = bytes_to_num(resp.d.asBytes + 24, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (par_list == 0 && c.arg[0] == true) {
|
||||
PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication.");
|
||||
PrintAndLog("Attack will take a few seconds longer because we need two consecutive successful runs.");
|
||||
}
|
||||
c.arg[0] = false;
|
||||
|
||||
keycount = nonce2key(uid, nt, nr, par_list, ks_list, &keylist);
|
||||
|
||||
if (keycount == 0) {
|
||||
PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);
|
||||
PrintAndLog("This is expected to happen in 25%% of all cases. Trying again with a different reader nonce...");
|
||||
continue;
|
||||
}
|
||||
|
||||
qsort(keylist, keycount, sizeof(*keylist), compare_uint64);
|
||||
keycount = intersection(last_keylist, keylist);
|
||||
if (keycount == 0) {
|
||||
free(last_keylist);
|
||||
last_keylist = keylist;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keycount > 1) {
|
||||
PrintAndLog("Found %u candidate keys. Trying to verify with authentication...\n", keycount);
|
||||
} else {
|
||||
PrintAndLog("Found a candidate key. Trying to verify it with authentication...\n");
|
||||
}
|
||||
|
||||
*key = -1;
|
||||
uint8_t keyBlock[USB_CMD_DATA_SIZE];
|
||||
int max_keys = USB_CMD_DATA_SIZE/6;
|
||||
for (int i = 0; i < keycount; i += max_keys) {
|
||||
int size = keycount - i > max_keys ? max_keys : keycount - i;
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (last_keylist == NULL) {
|
||||
num_to_bytes(keylist[i*max_keys + j], 6, keyBlock);
|
||||
} else {
|
||||
num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock);
|
||||
}
|
||||
}
|
||||
if (!mfCheckKeys(blockno, key_type - 0x60, false, size, keyBlock, key)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*key != -1) {
|
||||
free(last_keylist);
|
||||
free(keylist);
|
||||
break;
|
||||
} else {
|
||||
PrintAndLog("Test authentication failed. Restarting darkside attack");
|
||||
free(last_keylist);
|
||||
last_keylist = keylist;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){
|
||||
*key = 0;
|
||||
UsbCommand c = {CMD_MIFARE_CHKKEYS, { (blockNo | (keyType << 8)), clear_trace, keycnt}};
|
||||
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) return 1;
|
||||
if ((resp.arg[0] & 0xff) != 0x01) return 2;
|
||||
*key = bytes_to_num(resp.d.asBytes, 6);
|
||||
return 0;
|
||||
}
|
||||
// PM3 imp of J-Run mf_key_brute (part 2)
|
||||
// ref: https://github.com/J-Run/mf_key_brute
|
||||
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey){
|
||||
|
||||
#define KEYS_IN_BLOCK 85
|
||||
#define KEYBLOCK_SIZE 510
|
||||
#define CANDIDATE_SIZE 0xFFFF * 6
|
||||
uint8_t found = false;
|
||||
uint64_t key64 = 0;
|
||||
uint8_t candidates[CANDIDATE_SIZE] = {0x00};
|
||||
uint8_t keyBlock[KEYBLOCK_SIZE] = {0x00};
|
||||
|
||||
memset(candidates, 0, sizeof(candidates));
|
||||
memset(keyBlock, 0, sizeof(keyBlock));
|
||||
|
||||
// Generate all possible keys for the first two unknown bytes.
|
||||
for (uint16_t i = 0; i < 0xFFFF; ++i) {
|
||||
uint32_t j = i * 6;
|
||||
candidates[0 + j] = i >> 8;
|
||||
candidates[1 + j] = i;
|
||||
candidates[2 + j] = key[2];
|
||||
candidates[3 + j] = key[3];
|
||||
candidates[4 + j] = key[4];
|
||||
candidates[5 + j] = key[5];
|
||||
}
|
||||
uint32_t counter, i;
|
||||
for ( i = 0, counter = 1; i < CANDIDATE_SIZE; i += KEYBLOCK_SIZE, ++counter){
|
||||
|
||||
key64 = 0;
|
||||
|
||||
// copy candidatekeys to test key block
|
||||
memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE);
|
||||
|
||||
// check a block of generated candidate keys.
|
||||
if (!mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64)) {
|
||||
*resultkey = key64;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// progress
|
||||
if ( counter % 20 == 0 )
|
||||
PrintAndLog("tried : %s.. \t %u keys", sprint_hex(candidates + i, 6), counter * KEYS_IN_BLOCK );
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// Compare 16 Bits out of cryptostate
|
||||
int Compare16Bits(const void * a, const void * b) {
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1;
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) < (*(uint64_t*)a & 0x00ff000000ff0000)) return -1;
|
||||
return 0;
|
||||
|
||||
/* return
|
||||
((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000))
|
||||
-
|
||||
((*(uint64_t*)b & 0x00ff000000ff0000) < (*(uint64_t*)a & 0x00ff000000ff0000))
|
||||
;
|
||||
*/
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) < (*(uint64_t*)a & 0x00ff000000ff0000)) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// wrapper function for multi-threaded lfsr_recovery32
|
||||
|
@ -44,11 +267,12 @@ void* nested_worker_thread(void *arg)
|
|||
StateList_t *statelist = arg;
|
||||
statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid);
|
||||
|
||||
for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++);
|
||||
for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++) {};
|
||||
|
||||
statelist->len = p1 - statelist->head.slhead;
|
||||
statelist->tail.sltail = --p1;
|
||||
qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits);
|
||||
|
||||
return statelist->head.slhead;
|
||||
}
|
||||
|
||||
|
@ -129,27 +353,13 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
|
|||
statelists[1].tail.sltail = --p4;
|
||||
|
||||
// the statelists now contain possible keys. The key we are searching for must be in the
|
||||
// intersection of both lists. Create the intersection:
|
||||
qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compar_int);
|
||||
qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compar_int);
|
||||
|
||||
uint64_t *p5, *p6, *p7;
|
||||
p5 = p7 = statelists[0].head.keyhead;
|
||||
p6 = statelists[1].head.keyhead;
|
||||
|
||||
while (p5 <= statelists[0].tail.keytail && p6 <= statelists[1].tail.keytail) {
|
||||
if (compar_int(p5, p6) == 0) {
|
||||
*p7++ = *p5++;
|
||||
p6++;
|
||||
}
|
||||
else {
|
||||
while (compar_int(p5, p6) == -1) p5++;
|
||||
while (compar_int(p5, p6) == 1) p6++;
|
||||
}
|
||||
}
|
||||
statelists[0].len = p7 - statelists[0].head.keyhead;
|
||||
statelists[0].tail.keytail = --p7;
|
||||
// intersection of both lists
|
||||
qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64);
|
||||
qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64);
|
||||
// Create the intersection
|
||||
statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
|
||||
|
||||
//statelists[0].tail.keytail = --p7;
|
||||
uint32_t numOfCandidates = statelists[0].len;
|
||||
if ( numOfCandidates == 0 ) goto out;
|
||||
|
||||
|
@ -160,6 +370,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
|
|||
// uint32_t max_keys = keycnt > (USB_CMD_DATA_SIZE/6) ? (USB_CMD_DATA_SIZE/6) : keycnt;
|
||||
uint8_t keyBlock[USB_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
// ugly assumption that we have less than 85 candidate keys.
|
||||
for (i = 0; i < numOfCandidates; ++i){
|
||||
crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);
|
||||
num_to_bytes(key64, 6, keyBlock + i * 6);
|
||||
|
@ -191,65 +402,6 @@ out:
|
|||
return -4;
|
||||
}
|
||||
|
||||
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){
|
||||
*key = 0;
|
||||
UsbCommand c = {CMD_MIFARE_CHKKEYS, { (blockNo | (keyType << 8)), clear_trace, keycnt}};
|
||||
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) return 1;
|
||||
if ((resp.arg[0] & 0xff) != 0x01) return 2;
|
||||
*key = bytes_to_num(resp.d.asBytes, 6);
|
||||
return 0;
|
||||
}
|
||||
// PM3 imp of J-Run mf_key_brute (part 2)
|
||||
// ref: https://github.com/J-Run/mf_key_brute
|
||||
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey){
|
||||
|
||||
#define KEYS_IN_BLOCK 85
|
||||
#define KEYBLOCK_SIZE 510
|
||||
#define CANDIDATE_SIZE 0xFFFF * 6
|
||||
uint8_t found = false;
|
||||
uint64_t key64 = 0;
|
||||
uint8_t candidates[CANDIDATE_SIZE] = {0x00};
|
||||
uint8_t keyBlock[KEYBLOCK_SIZE] = {0x00};
|
||||
|
||||
memset(candidates, 0, sizeof(candidates));
|
||||
memset(keyBlock, 0, sizeof(keyBlock));
|
||||
|
||||
// Generate all possible keys for the first two unknown bytes.
|
||||
for (uint16_t i = 0; i < 0xFFFF; ++i) {
|
||||
uint32_t j = i * 6;
|
||||
candidates[0 + j] = i >> 8;
|
||||
candidates[1 + j] = i;
|
||||
candidates[2 + j] = key[2];
|
||||
candidates[3 + j] = key[3];
|
||||
candidates[4 + j] = key[4];
|
||||
candidates[5 + j] = key[5];
|
||||
}
|
||||
uint32_t counter, i;
|
||||
for ( i = 0, counter = 1; i < CANDIDATE_SIZE; i += KEYBLOCK_SIZE, ++counter){
|
||||
|
||||
key64 = 0;
|
||||
|
||||
// copy candidatekeys to test key block
|
||||
memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE);
|
||||
|
||||
// check a block of generated candidate keys.
|
||||
if (!mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64)) {
|
||||
*resultkey = key64;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// progress
|
||||
if ( counter % 20 == 0 )
|
||||
PrintAndLog("tried : %s.. \t %u keys", sprint_hex(candidates + i, 6), counter * KEYS_IN_BLOCK );
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// EMULATOR
|
||||
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {
|
||||
UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "ui.h"
|
||||
#include "data.h"
|
||||
#include "util.h"
|
||||
#include "nonce2key/crapto1.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "iso14443crc.h"
|
||||
#include "protocols.h"
|
||||
#include "mifare.h"
|
||||
|
@ -60,31 +60,31 @@ typedef struct {
|
|||
uint64_t Key[2];
|
||||
int foundKey[2];
|
||||
} sector_t;
|
||||
|
||||
extern int compar_int(const void * a, const void * b);
|
||||
|
||||
extern char logHexFileName[FILE_PATH_SIZE];
|
||||
|
||||
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);
|
||||
int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);
|
||||
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
|
||||
extern int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key);
|
||||
extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);
|
||||
extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);
|
||||
extern int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
|
||||
|
||||
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||
extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
extern int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||
|
||||
int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard);
|
||||
int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
||||
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||
extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard);
|
||||
extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
||||
extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||
|
||||
int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile);
|
||||
int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile);
|
||||
extern int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile);
|
||||
extern int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile);
|
||||
|
||||
int isTraceCardEmpty(void);
|
||||
int isBlockEmpty(int blockN);
|
||||
int isBlockTrailer(int blockN);
|
||||
int loadTraceCard(uint8_t *tuid, uint8_t uidlen);
|
||||
int saveTraceCard(void);
|
||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
extern int isTraceCardEmpty(void);
|
||||
extern int isBlockEmpty(int blockN);
|
||||
extern int isBlockTrailer(int blockN);
|
||||
extern int loadTraceCard(uint8_t *tuid, uint8_t uidlen);
|
||||
extern int saveTraceCard(void);
|
||||
extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
|
||||
extern bool detect_classic_prng();
|
||||
#endif
|
|
@ -106,35 +106,12 @@ static int returnToLuaWithError(lua_State *L, const char* fmt, ...)
|
|||
return 2;
|
||||
}
|
||||
|
||||
static int l_nonce2key(lua_State *L){
|
||||
|
||||
size_t size;
|
||||
const char *p_uid = luaL_checklstring(L, 1, &size);
|
||||
if(size != 4) return returnToLuaWithError(L,"Wrong size of uid, got %d bytes, expected 4", (int) size);
|
||||
|
||||
const char *p_nt = luaL_checklstring(L, 2, &size);
|
||||
if(size != 4) return returnToLuaWithError(L,"Wrong size of nt, got %d bytes, expected 4", (int) size);
|
||||
|
||||
const char *p_nr = luaL_checklstring(L, 3, &size);
|
||||
if(size != 4) return returnToLuaWithError(L,"Wrong size of nr, got %d bytes, expected 4", (int) size);
|
||||
|
||||
const char *p_par_info = luaL_checklstring(L, 4, &size);
|
||||
if(size != 8) return returnToLuaWithError(L,"Wrong size of par_info, got %d bytes, expected 8", (int) size);
|
||||
|
||||
const char *p_pks_info = luaL_checklstring(L, 5, &size);
|
||||
if(size != 8) return returnToLuaWithError(L,"Wrong size of ks_info, got %d bytes, expected 8", (int) size);
|
||||
|
||||
|
||||
uint32_t uid = bytes_to_num(( uint8_t *)p_uid,4);
|
||||
uint32_t nt = bytes_to_num(( uint8_t *)p_nt,4);
|
||||
|
||||
uint32_t nr = bytes_to_num(( uint8_t*)p_nr,4);
|
||||
uint64_t par_info = bytes_to_num(( uint8_t *)p_par_info,8);
|
||||
uint64_t ks_info = bytes_to_num(( uint8_t *)p_pks_info,8);
|
||||
|
||||
uint64_t key = 0;
|
||||
|
||||
int retval = nonce2key(uid,nt, nr, par_info,ks_info, &key);
|
||||
static int l_mfDarkside(lua_State *L){
|
||||
// blockno, keytype
|
||||
|
||||
uint64_t key;
|
||||
|
||||
int retval = mfDarkside(0, 0, &key);
|
||||
|
||||
//Push the retval on the stack
|
||||
lua_pushinteger(L,retval);
|
||||
|
@ -519,7 +496,8 @@ static int l_hardnested(lua_State *L){
|
|||
}
|
||||
|
||||
uint64_t foundkey = 0;
|
||||
int retval = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, haveTarget ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey);
|
||||
// int retval = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, haveTarget ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey);
|
||||
int retval = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, haveTarget ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests);
|
||||
|
||||
//Push the retval on the stack
|
||||
lua_pushinteger(L,retval);
|
||||
|
@ -560,7 +538,7 @@ int set_pm3_libraries(lua_State *L) {
|
|||
static const luaL_Reg libs[] = {
|
||||
{"SendCommand", l_SendCommand},
|
||||
{"WaitForResponseTimeout", l_WaitForResponseTimeout},
|
||||
{"nonce2key", l_nonce2key},
|
||||
{"mfDarkside", l_mfDarkside},
|
||||
//{"PrintAndLog", l_PrintAndLog},
|
||||
{"foobar", l_foobar},
|
||||
{"ukbhit", l_ukbhit},
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef SCRIPTING_H__
|
||||
#define SCRIPTING_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
@ -17,7 +18,7 @@
|
|||
#include "usb_cmd.h"
|
||||
#include "cmdmain.h"
|
||||
#include "util.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "mifarehost.h"
|
||||
#include "../common/iso15693tools.h"
|
||||
#include "iso14443crc.h"
|
||||
#include "../common/crc.h"
|
||||
|
|
|
@ -63,90 +63,6 @@ function wait_for_mifare()
|
|||
return nil, "Aborted by user"
|
||||
end
|
||||
|
||||
function mfcrack()
|
||||
core.clearCommandBuffer()
|
||||
-- Build the mifare-command
|
||||
local cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 1, arg2 = 0, arg3 = MIFARE_AUTH_KEYA}
|
||||
|
||||
local retry = true
|
||||
while retry do
|
||||
core.SendCommand(cmd:getBytes())
|
||||
local key, errormessage = mfcrack_inner()
|
||||
-- Success?
|
||||
if key then return key end
|
||||
-- Failure?
|
||||
if errormessage then return nil, errormessage end
|
||||
-- Try again..set arg1 to 0 this time.
|
||||
|
||||
cmd = Command:new{cmd = cmds.CMD_READER_MIFARE, arg1 = 0, arg2 = 0, arg3 = MIFARE_AUTH_KEYA}
|
||||
end
|
||||
return nil, "Aborted by user"
|
||||
end
|
||||
|
||||
function mfcrack_inner()
|
||||
while not core.ukbhit() do
|
||||
local result = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
|
||||
if result then
|
||||
|
||||
--[[
|
||||
I don't understand, they cmd and args are defined as uint32_t, however,
|
||||
looking at the returned data, they all look like 64-bit things:
|
||||
|
||||
print("result", bin.unpack("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", result))
|
||||
|
||||
FF 00 00 00 00 00 00 00 <-- 64 bits of data
|
||||
FE FF FF FF 00 00 00 00 <-- 64 bits of data
|
||||
00 00 00 00 00 00 00 00 <-- 64 bits of data
|
||||
00 00 00 00 00 00 00 00 <-- 64 bits of data
|
||||
04 7F 12 E2 00 <-- this is where 'data' starts
|
||||
|
||||
So below I use LI to pick out the "FEFF FFFF", don't know why it works..
|
||||
--]]
|
||||
-- Unpacking the arg-parameters
|
||||
local count,cmd,isOK = bin.unpack('LI',result)
|
||||
--print("response", isOK)--FF FF FF FF
|
||||
if isOK == 0xFFFFFFFF then
|
||||
return nil, "Button pressed. Aborted."
|
||||
elseif isOK == 0xFFFFFFFE then
|
||||
return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
|
||||
elseif isOK == 0xFFFFFFFD then
|
||||
return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
|
||||
elseif isOK == 0xFFFFFFFC then
|
||||
return nil, "The card's random number generator behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys."
|
||||
elseif isOK ~= 1 then
|
||||
return nil, "Error occurred"
|
||||
end
|
||||
|
||||
|
||||
-- The data-part is left
|
||||
-- Starts 32 bytes in, at byte 33
|
||||
local data = result:sub(33)
|
||||
|
||||
-- A little helper
|
||||
local get = function(num)
|
||||
local x = data:sub(1,num)
|
||||
data = data:sub(num+1)
|
||||
return x
|
||||
end
|
||||
|
||||
local uid,nt,pl = get(4),get(4),get(8)
|
||||
local ks,nr = get(8),get(4)
|
||||
|
||||
local status, key = core.nonce2key(uid, nt, nr, pl, ks)
|
||||
if not status then return status,key end
|
||||
|
||||
if status > 0 then
|
||||
print("Key not found (lfsr_common_prefix problem)")
|
||||
-- try again
|
||||
return nil,nil
|
||||
else
|
||||
return key
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil, "Aborted by user"
|
||||
end
|
||||
|
||||
function nested(key,sak)
|
||||
local typ = 1
|
||||
if 0x18 == sak then --NXP MIFARE Classic 4k | Plus 4k | Ev1 4k
|
||||
|
@ -211,8 +127,15 @@ function main(args)
|
|||
print("Card found, commencing crack on UID", uid)
|
||||
-- Crack it
|
||||
local key, cnt
|
||||
res,err = mfcrack()
|
||||
if not res then return oops(err) end
|
||||
err, res = core.mfDarkside()
|
||||
if err == -1 then return oops("Button pressed. Aborted.")
|
||||
elseif err == -2 then return oops("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).")
|
||||
elseif err == -3 then return oops("Card is not vulnerable to Darkside attack (its random number generator is not predictable).")
|
||||
elseif err == -4 then return oops([[
|
||||
Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown
|
||||
generating polynomial with 16 effective bits only, but shows unexpected behaviour.]])
|
||||
elseif err == -5 then return oops("Aborted via keyboard.")
|
||||
end
|
||||
-- The key is actually 8 bytes, so a
|
||||
-- 6-byte key is sent as 00XXXXXX
|
||||
-- This means we unpack it as first
|
||||
|
|
|
@ -69,7 +69,7 @@ endif
|
|||
#COMMON_FLAGS += -DHAS_512_FLASH
|
||||
|
||||
# Also search prerequisites in the common directory (for usb.c), the fpga directory (for fpga.bit), and the zlib directory
|
||||
VPATH = . ../common ../fpga ../zlib
|
||||
VPATH = . ../common ../fpga ../zlib --/uart
|
||||
|
||||
INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
bool cmd_receive(UsbCommand* cmd) {
|
||||
|
||||
// Check if there is a usb packet available
|
||||
if (!usb_poll()) return false;
|
||||
if (!usb_poll_validate_length()) return false;
|
||||
|
||||
// Try to retrieve the available command frame
|
||||
size_t rxlen = usb_read((byte_t*)cmd,sizeof(UsbCommand));
|
||||
|
|
|
@ -71,16 +71,17 @@ typedef enum ISO14B_COMMAND {
|
|||
// "hf 14a sim x", "hf mf sim x" attacks
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
uint32_t cuid;
|
||||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
uint8_t sector;
|
||||
uint8_t keytype;
|
||||
enum {
|
||||
uint32_t cuid;
|
||||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t at;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
uint8_t sector;
|
||||
uint8_t keytype;
|
||||
enum {
|
||||
EMPTY,
|
||||
FIRST,
|
||||
SECOND,
|
||||
|
|
Loading…
Reference in a new issue