mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-16 02:03:00 -07:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
bad2eb8587
19 changed files with 1579 additions and 1713 deletions
|
@ -58,7 +58,7 @@ CORESRCS = uart.c \
|
|||
|
||||
CMDSRCS = crapto1/crapto1.c\
|
||||
crapto1/crypto1.c\
|
||||
nonce2key/nonce2key.c\
|
||||
nonce2key.c\
|
||||
loclass/cipher.c \
|
||||
loclass/cipherutils.c \
|
||||
loclass/des.c \
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||
uint8_t g_debugMode=0;
|
||||
size_t DemodBufferLen=0;
|
||||
//size_t g_demodStartIdx=0;
|
||||
//uint8_t g_demodClock=0;
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
//set the demod buffer with given array of binary (one bit per byte)
|
||||
|
@ -253,6 +256,7 @@ void printEM410x(uint32_t hi, uint64_t id)
|
|||
return;
|
||||
}
|
||||
|
||||
//should be moved to cmdlfem4x.c
|
||||
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo )
|
||||
{
|
||||
size_t idx = 0;
|
||||
|
@ -274,7 +278,7 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo )
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//should be moved to cmdlfem4x.c
|
||||
int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose)
|
||||
{
|
||||
bool st = true;
|
||||
|
@ -282,6 +286,7 @@ int AskEm410xDemod(const char *Cmd, uint32_t *hi, uint64_t *lo, bool verbose)
|
|||
return AskEm410xDecode(verbose, hi, lo);
|
||||
}
|
||||
|
||||
//should be moved to cmdlfem4x.c
|
||||
//by marshmellow
|
||||
//takes 3 arguments - clock, invert and maxErr as integers
|
||||
//attempts to demodulate ask while decoding manchester
|
||||
|
@ -451,7 +456,8 @@ int Cmdmandecoderaw(const char *Cmd)
|
|||
|
||||
sscanf(Cmd, "%i %i", &invert, &maxErr);
|
||||
size=i;
|
||||
errCnt=manrawdecode(BitStream, &size, invert);
|
||||
uint8_t alignPos = 0;
|
||||
errCnt=manrawdecode(BitStream, &size, invert, &alignPos);
|
||||
if (errCnt>=maxErr){
|
||||
PrintAndLog("Too many errors: %d",errCnt);
|
||||
return 0;
|
||||
|
@ -590,6 +596,7 @@ int Cmdaskbiphdemod(const char *Cmd)
|
|||
return ASKbiphaseDemod(Cmd, true);
|
||||
}
|
||||
|
||||
//could be split to a gProxII file
|
||||
//by marshmellow
|
||||
//attempts to demodulate and identify a G_Prox_II verex/chubb card
|
||||
//WARNING: if it fails during some points it will destroy the DemodBuffer data
|
||||
|
@ -655,6 +662,7 @@ int CmdG_Prox_II_Demod(const char *Cmd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
//could be moved to a viking file
|
||||
//by marshmellow
|
||||
//see ASKDemod for what args are accepted
|
||||
int CmdVikingDemod(const char *Cmd)
|
||||
|
@ -1038,6 +1046,7 @@ int CmdFSKrawdemod(const char *Cmd)
|
|||
return FSKrawDemod(Cmd, true);
|
||||
}
|
||||
|
||||
//move to cmdlfhid.c
|
||||
//by marshmellow (based on existing demod + holiman's refactor)
|
||||
//HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded)
|
||||
//print full HID Prox ID and some bit format details if found
|
||||
|
@ -1124,6 +1133,7 @@ int CmdFSKdemodHID(const char *Cmd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//by marshmellow
|
||||
//Paradox Prox demod - FSK RF/50 with preamble of 00001111 (then manchester encoded)
|
||||
//print full Paradox Prox ID and some bit format details if found
|
||||
|
@ -1751,7 +1761,8 @@ int NRZrawDemod(const char *Cmd, bool verbose)
|
|||
size_t BitLen = getFromGraphBuf(BitStream);
|
||||
if (BitLen==0) return 0;
|
||||
int errCnt=0;
|
||||
errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert);
|
||||
int clkStartIdx = 0;
|
||||
errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert, &clkStartIdx);
|
||||
if (errCnt > maxErr){
|
||||
if (g_debugMode) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt);
|
||||
return 0;
|
||||
|
@ -2264,13 +2275,13 @@ int CmdDirectionalThreshold(const char *Cmd)
|
|||
if (GraphBuffer[i] >= upThres && GraphBuffer[i] > lastValue)
|
||||
{
|
||||
lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it.
|
||||
GraphBuffer[i] = 1;
|
||||
GraphBuffer[i] = 127;
|
||||
}
|
||||
// Apply second threshold to samples heading down
|
||||
else if (GraphBuffer[i] <= downThres && GraphBuffer[i] < lastValue)
|
||||
{
|
||||
lastValue = GraphBuffer[i]; // Buffer last value as we overwrite it.
|
||||
GraphBuffer[i] = -1;
|
||||
GraphBuffer[i] = -127;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -19,91 +19,35 @@
|
|||
#include "ui.h"
|
||||
#include "mifarehost.h"
|
||||
#include "mifare.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "nonce2key.h"
|
||||
|
||||
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
|
||||
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
||||
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 isOK = 0;
|
||||
uint64_t key = 0;
|
||||
|
||||
UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}};
|
||||
|
||||
// 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");
|
||||
|
||||
|
||||
start:
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
//flush queue
|
||||
while (ukbhit()) {
|
||||
int c = getchar(); (void) c;
|
||||
}
|
||||
|
||||
// wait cycle
|
||||
while (true) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
if (ukbhit()) {
|
||||
getchar();
|
||||
printf("\naborted via keyboard!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
|
||||
isOK = resp.arg[0];
|
||||
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);
|
||||
printf("\n\n");
|
||||
switch (isOK) {
|
||||
case -1 : PrintAndLog("Button pressed. Aborted.\n"); break;
|
||||
case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break;
|
||||
case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break;
|
||||
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.\n"); break;
|
||||
default: ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// error
|
||||
if (isOK != 1) return 1;
|
||||
|
||||
// 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 {
|
||||
isOK = 0;
|
||||
printf("------------------------------------------------------------------\n");
|
||||
PrintAndLog("Found valid key:%012" PRIx64 " \n", r_key);
|
||||
isOK = mfDarkside(&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);
|
||||
}
|
||||
|
||||
PrintAndLog("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CmdHF14AMfWrBl(const char *Cmd)
|
||||
{
|
||||
uint8_t blockNo = 0;
|
||||
|
@ -1090,7 +1034,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (tryMfk32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) {
|
||||
} else if (mfkey32_moebius(ar_resp[i+ATTACK_KEY_COUNT], &key)) {
|
||||
uint8_t sectorNum = ar_resp[i+ATTACK_KEY_COUNT].sector;
|
||||
uint8_t keyType = ar_resp[i+ATTACK_KEY_COUNT].keytype;
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ int CmdCOTAGDemod(const char *Cmd) {
|
|||
size_t bitlen = COTAG_BITS;
|
||||
memcpy(bits, DemodBuffer, COTAG_BITS);
|
||||
|
||||
int err = manrawdecode(bits, &bitlen, 1);
|
||||
uint8_t alignPos = 0;
|
||||
int err = manrawdecode(bits, &bitlen, 1, &alignPos);
|
||||
if (err){
|
||||
if (g_debugMode) PrintAndLog("DEBUG: Error - COTAG too many errors: %d", err);
|
||||
return -1;
|
||||
|
|
|
@ -218,7 +218,8 @@ uint8_t GetNrzClock(const char str[], bool printAns, bool verbose)
|
|||
PrintAndLog("Failed to copy from graphbuffer");
|
||||
return -1;
|
||||
}
|
||||
clock = DetectNRZClock(grph, size, 0);
|
||||
size_t clkStartIdx = 0;
|
||||
clock = DetectNRZClock(grph, size, 0, &clkStartIdx);
|
||||
// Only print this message if we're not looping something
|
||||
if (printAns){
|
||||
PrintAndLog("Auto-detected clock rate: %d", clock);
|
||||
|
|
|
@ -33,7 +33,194 @@
|
|||
#define TRACE_ERROR 0xFF
|
||||
|
||||
|
||||
// MIFARE
|
||||
static int compare_uint64(const void *a, const void *b) {
|
||||
// didn't work: (the result is truncated to 32 bits)
|
||||
//return (*(int64_t*)b - *(int64_t*)a);
|
||||
|
||||
// better:
|
||||
if (*(uint64_t*)b == *(uint64_t*)a) return 0;
|
||||
else if (*(uint64_t*)b < *(uint64_t*)a) return 1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
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; //nr_diff;
|
||||
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 == NULL) {
|
||||
*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(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, 0, 0}};
|
||||
|
||||
// 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 c = getchar(); (void) c;
|
||||
}
|
||||
|
||||
// wait cycle
|
||||
while (true) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
if (ukbhit()) {
|
||||
return -5;
|
||||
break;
|
||||
}
|
||||
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
|
||||
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 possible keys. Trying to authenticate with each of them ...\n", keycount);
|
||||
} else {
|
||||
PrintAndLog("Found a possible key. Trying to authenticate...\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(0, 0, false, size, keyBlock, key)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*key != -1) {
|
||||
free(last_keylist);
|
||||
free(keylist);
|
||||
break;
|
||||
} else {
|
||||
PrintAndLog("Authentication failed. Trying again...");
|
||||
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;
|
||||
|
@ -49,16 +236,6 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key
|
|||
return 0;
|
||||
}
|
||||
|
||||
int compar_int(const void * a, const void * b) {
|
||||
// didn't work: (the result is truncated to 32 bits)
|
||||
//return (*(uint64_t*)b - *(uint64_t*)a);
|
||||
|
||||
// better:
|
||||
if (*(uint64_t*)b == *(uint64_t*)a) return 0;
|
||||
else if (*(uint64_t*)b > *(uint64_t*)a) return 1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
// Compare 16 Bits out of cryptostate
|
||||
int Compare16Bits(const void * a, const void * b) {
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;
|
||||
|
@ -100,7 +277,7 @@ void* nested_worker_thread(void *arg)
|
|||
return statelist->head.slhead;
|
||||
}
|
||||
|
||||
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKey, bool calibrate)
|
||||
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate)
|
||||
{
|
||||
uint16_t i;
|
||||
uint32_t uid;
|
||||
|
@ -178,8 +355,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
|
|||
while (Compare16Bits(p1, p2) == 1) p2++;
|
||||
}
|
||||
}
|
||||
p3->even = 0; p3->odd = 0;
|
||||
p4->even = 0; p4->odd = 0;
|
||||
*(uint64_t*)p3 = -1;
|
||||
*(uint64_t*)p4 = -1;
|
||||
statelists[0].len = p3 - statelists[0].head.slhead;
|
||||
statelists[1].len = p4 - statelists[1].head.slhead;
|
||||
statelists[0].tail.sltail=--p3;
|
||||
|
@ -187,24 +364,9 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo
|
|||
|
||||
// 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;
|
||||
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);
|
||||
statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead);
|
||||
|
||||
memset(resultKey, 0, 6);
|
||||
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
|
||||
extern char logHexFileName[FILE_PATH_SIZE];
|
||||
|
||||
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 mfDarkside(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 mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
|
|
137
client/nonce2key.c
Normal file
137
client/nonce2key.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Merlok - June 2011
|
||||
// Roel - Dec 2009
|
||||
// Unknown author
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Darkside hack
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "nonce2key.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mifarehost.h"
|
||||
#include "util.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
|
||||
// recover key from 2 different reader responses on same tag challenge
|
||||
bool mfkey32(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s,*t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key = 0; // recovered key
|
||||
bool isSuccess = false;
|
||||
uint8_t counter = 0;
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, data.nr, 1);
|
||||
lfsr_rollback_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
crypto1_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_word(t, data.nr2, 1);
|
||||
if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce, 64))) {
|
||||
//PrintAndLog("Found Key: [%012" PRIx64 "]",key);
|
||||
outkey = key;
|
||||
counter++;
|
||||
if (counter == 20) break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
t1 = msclock() - t1;
|
||||
//if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
/* //un-comment to save all keys to a stats.txt file
|
||||
FILE *fout;
|
||||
if ((fout = fopen("stats.txt","ab")) == NULL) {
|
||||
PrintAndLog("Could not create file name stats.txt");
|
||||
return 1;
|
||||
}
|
||||
fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1);
|
||||
fclose(fout);
|
||||
*/
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// recover key from 2 reader responses on 2 different tag challenges
|
||||
bool mfkey32_moebius(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s, *t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key = 0; // recovered key
|
||||
bool isSuccess = false;
|
||||
int counter = 0;
|
||||
|
||||
//PrintAndLog("Enter mfkey32_moebius");
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
s = lfsr_recovery32(data.ar ^ prng_successor(data.nonce, 64), 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, data.nr, 1);
|
||||
lfsr_rollback_word(t, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
|
||||
crypto1_word(t, data.cuid ^ data.nonce2, 0);
|
||||
crypto1_word(t, data.nr2, 1);
|
||||
if (data.ar2 == (crypto1_word(t, 0, 0) ^ prng_successor(data.nonce2, 64))) {
|
||||
//PrintAndLog("Found Key: [%012" PRIx64 "]",key);
|
||||
outkey=key;
|
||||
++counter;
|
||||
if (counter==20)
|
||||
break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
t1 = msclock() - t1;
|
||||
// PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
/* // un-comment to output all keys to stats.txt
|
||||
FILE *fout;
|
||||
if ((fout = fopen("stats.txt","ab")) == NULL) {
|
||||
PrintAndLog("Could not create file name stats.txt");
|
||||
return 1;
|
||||
}
|
||||
fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1);
|
||||
fclose(fout);
|
||||
*/
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// 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
|
||||
struct Crypto1State *revstate;
|
||||
|
||||
// PrintAndLog("Enter mfkey64");
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
// Extract the keystream from the messages
|
||||
ks2 = data.ar ^ prng_successor(data.nonce, 64);
|
||||
ks3 = data.at ^ prng_successor(data.nonce, 96);
|
||||
revstate = lfsr_recovery64(ks2, ks3);
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, 0, 0);
|
||||
lfsr_rollback_word(revstate, data.nr, 1);
|
||||
lfsr_rollback_word(revstate, data.cuid ^ data.nonce, 0);
|
||||
crypto1_get_lfsr(revstate, &key);
|
||||
// PrintAndLog("Found Key: [%012" PRIx64 "]", key);
|
||||
crypto1_destroy(revstate);
|
||||
*outputkey = key;
|
||||
|
||||
t1 = msclock() - t1;
|
||||
// PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0);
|
||||
return 0;
|
||||
}
|
|
@ -23,17 +23,14 @@ typedef struct {
|
|||
uint32_t nonce;
|
||||
uint32_t ar;
|
||||
uint32_t nr;
|
||||
uint32_t at;
|
||||
uint32_t nonce2;
|
||||
uint32_t ar2;
|
||||
uint32_t nr2;
|
||||
} nonces_t;
|
||||
|
||||
int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key);
|
||||
bool mfkey32(nonces_t data, uint64_t *outputkey);
|
||||
bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey);
|
||||
int tryMfk64_ex(uint8_t *data, uint64_t *outputkey);
|
||||
int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, uint64_t *outputkey);
|
||||
|
||||
//uint64_t mfkey32(uint32_t uid, uint32_t nt, uint32_t nr0_enc, uint32_t ar0_enc, uint32_t nr1_enc, uint32_t ar1_enc);
|
||||
bool mfkey32_moebius(nonces_t data, uint64_t *outputkey);
|
||||
int mfkey64(nonces_t data, uint64_t *outputkey);
|
||||
|
||||
#endif
|
|
@ -1,288 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Merlok - June 2011
|
||||
// Roel - Dec 2009
|
||||
// Unknown author
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Darkside hack
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "nonce2key.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mifarehost.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
|
||||
int compar_state(const void * a, const void * b) {
|
||||
// didn't work: (the result is truncated to 32 bits)
|
||||
//return (*(int64_t*)b - *(int64_t*)a);
|
||||
|
||||
// better:
|
||||
if (*(int64_t*)b == *(int64_t*)a) return 0;
|
||||
else if (*(int64_t*)b > *(int64_t*)a) return 1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint64_t par_info, uint64_t ks_info, uint64_t * key) {
|
||||
struct Crypto1State *state;
|
||||
uint32_t i, pos, rr, nr_diff, key_count;//, ks1, ks2;
|
||||
uint8_t bt, ks3x[8], par[8][8];
|
||||
uint64_t key_recovered;
|
||||
int64_t *state_s;
|
||||
static uint32_t last_uid;
|
||||
static int64_t *last_keylist;
|
||||
rr = 0;
|
||||
|
||||
if (last_uid != uid && last_keylist != NULL)
|
||||
{
|
||||
free(last_keylist);
|
||||
last_keylist = NULL;
|
||||
}
|
||||
last_uid = uid;
|
||||
|
||||
// Reset the last three significant bits of the reader nonce
|
||||
nr &= 0xffffff1f;
|
||||
|
||||
PrintAndLog("\nuid(%08x) nt(%08x) par(%016" PRIx64") ks(%016" PRIx64") nr(%08" PRIx32")\n\n",uid,nt,par_info,ks_info,nr);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
printf("|diff|{nr} |ks3|ks3^5|parity |\n");
|
||||
printf("+----+--------+---+-----+---------------+\n");
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
nr_diff = nr | i << 5;
|
||||
printf("| %02x |%08x|",i << 5, nr_diff);
|
||||
printf(" %01x | %01x |",ks3x[i], ks3x[i]^5);
|
||||
for (pos=0; pos<7; pos++) printf("%01x,", par[i][pos]);
|
||||
printf("%01x|\n", par[i][7]);
|
||||
}
|
||||
|
||||
if (par_info == 0)
|
||||
PrintAndLog("Parity is all zero, trying special attack! Just wait for few more seconds...");
|
||||
|
||||
state = lfsr_common_prefix(nr, rr, ks3x, par);
|
||||
state_s = (int64_t*)state;
|
||||
|
||||
//char filename[50] ;
|
||||
//sprintf(filename, "nt_%08x_%d.txt", nt, nr);
|
||||
//printf("name %s\n", filename);
|
||||
//FILE* fp = fopen(filename,"w");
|
||||
for (i = 0; (state) && *(state_s + i); i++)
|
||||
{
|
||||
lfsr_rollback_word(state+i, uid^nt, 0);
|
||||
crypto1_get_lfsr(state + i, &key_recovered);
|
||||
*(state_s + i) = key_recovered;
|
||||
//fprintf(fp, "%012" PRIx64 "\n",key_recovered);
|
||||
}
|
||||
//fclose(fp);
|
||||
|
||||
if(!state)
|
||||
return 1;
|
||||
|
||||
qsort(state_s, i, sizeof(*state_s), compar_state);
|
||||
*(state_s + i) = -1;
|
||||
|
||||
//Create the intersection:
|
||||
if (par_info == 0 ) {
|
||||
if (last_keylist != NULL) {
|
||||
int64_t *p1, *p2, *p3;
|
||||
p1 = p3 = last_keylist;
|
||||
p2 = state_s;
|
||||
while ( *p1 != -1 && *p2 != -1 ) {
|
||||
if (compar_state(p1, p2) == 0) {
|
||||
printf("p1:%" PRIx64" p2:%" PRIx64 " p3:%" PRIx64" key:%012" PRIx64 "\n",(uint64_t)(p1-last_keylist),(uint64_t)(p2-state_s),(uint64_t)(p3-last_keylist),*p1);
|
||||
*p3++ = *p1++;
|
||||
p2++;
|
||||
}
|
||||
else {
|
||||
while (compar_state(p1, p2) == -1) ++p1;
|
||||
while (compar_state(p1, p2) == 1) ++p2;
|
||||
}
|
||||
}
|
||||
key_count = p3 - last_keylist;
|
||||
} else {
|
||||
key_count = 0;
|
||||
}
|
||||
} else {
|
||||
last_keylist = state_s;
|
||||
key_count = i;
|
||||
}
|
||||
|
||||
printf("key_count:%d\n", key_count);
|
||||
|
||||
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
||||
for (i = 0; i < key_count; i++) {
|
||||
uint8_t keyBlock[6];
|
||||
uint64_t key64;
|
||||
key64 = *(last_keylist + i);
|
||||
num_to_bytes(key64, 6, keyBlock);
|
||||
key64 = 0;
|
||||
if (!mfCheckKeys(0, 0, false, 1, keyBlock, &key64)) {
|
||||
*key = key64;
|
||||
free(last_keylist);
|
||||
last_keylist = NULL;
|
||||
if (par_info == 0)
|
||||
free(state);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(last_keylist);
|
||||
last_keylist = state_s;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 32 bit recover key from 2 nonces
|
||||
bool mfkey32(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s,*t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key=0; // recovered key
|
||||
uint32_t uid = data.cuid;
|
||||
uint32_t nt = data.nonce; // first tag challenge (nonce)
|
||||
uint32_t nr0_enc = data.nr; // first encrypted reader challenge
|
||||
uint32_t ar0_enc = data.ar; // first encrypted reader response
|
||||
uint32_t nr1_enc = data.nr2; // second encrypted reader challenge
|
||||
uint32_t ar1_enc = data.ar2; // second encrypted reader response
|
||||
uint64_t t1 = msclock();
|
||||
bool isSuccess = false;
|
||||
uint8_t counter=0;
|
||||
|
||||
s = lfsr_recovery32(ar0_enc ^ prng_successor(nt, 64), 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, nr0_enc, 1);
|
||||
lfsr_rollback_word(t, uid ^ nt, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
crypto1_word(t, uid ^ nt, 0);
|
||||
crypto1_word(t, nr1_enc, 1);
|
||||
if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt, 64))) {
|
||||
//PrintAndLog("Found Key: [%012" PRIx64 "]",key);
|
||||
outkey = key;
|
||||
counter++;
|
||||
if (counter==20) break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
t1 = msclock() - t1;
|
||||
//if ( t1 > 0 ) PrintAndLog("Time in mfkey32: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
/* //un-comment to save all keys to a stats.txt file
|
||||
FILE *fout;
|
||||
if ((fout = fopen("stats.txt","ab")) == NULL) {
|
||||
PrintAndLog("Could not create file name stats.txt");
|
||||
return 1;
|
||||
}
|
||||
fprintf(fout, "mfkey32,%d,%08x,%d,%s,%04x%08x,%.0Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t)(outkey>>32) & 0xFFFF,(uint32_t)(outkey&0xFFFFFFFF),(long double)t1);
|
||||
fclose(fout);
|
||||
*/
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
bool tryMfk32_moebius(nonces_t data, uint64_t *outputkey) {
|
||||
struct Crypto1State *s, *t;
|
||||
uint64_t outkey = 0;
|
||||
uint64_t key = 0; // recovered key
|
||||
uint32_t uid = data.cuid;
|
||||
uint32_t nt0 = data.nonce; // first tag challenge (nonce)
|
||||
uint32_t nr0_enc = data.nr; // first encrypted reader challenge
|
||||
uint32_t ar0_enc = data.ar; // first encrypted reader response
|
||||
uint32_t nt1 = data.nonce2; // second tag challenge (nonce)
|
||||
uint32_t nr1_enc = data.nr2; // second encrypted reader challenge
|
||||
uint32_t ar1_enc = data.ar2; // second encrypted reader response
|
||||
bool isSuccess = false;
|
||||
int counter = 0;
|
||||
|
||||
//PrintAndLog("Enter mfkey32_moebius");
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
s = lfsr_recovery32(ar0_enc ^ prng_successor(nt0, 64), 0);
|
||||
|
||||
for(t = s; t->odd | t->even; ++t) {
|
||||
lfsr_rollback_word(t, 0, 0);
|
||||
lfsr_rollback_word(t, nr0_enc, 1);
|
||||
lfsr_rollback_word(t, uid ^ nt0, 0);
|
||||
crypto1_get_lfsr(t, &key);
|
||||
|
||||
crypto1_word(t, uid ^ nt1, 0);
|
||||
crypto1_word(t, nr1_enc, 1);
|
||||
if (ar1_enc == (crypto1_word(t, 0, 0) ^ prng_successor(nt1, 64))) {
|
||||
//PrintAndLog("Found Key: [%012" PRIx64 "]",key);
|
||||
outkey=key;
|
||||
++counter;
|
||||
if (counter==20)
|
||||
break;
|
||||
}
|
||||
}
|
||||
isSuccess = (counter == 1);
|
||||
t1 = msclock() - t1;
|
||||
//if ( t1 > 0 ) PrintAndLog("Time in mfkey32_moebius: %.1f seconds \nFound %d possible keys", (float)t1/1000.0, counter);
|
||||
*outputkey = ( isSuccess ) ? outkey : 0;
|
||||
crypto1_destroy(s);
|
||||
/* // un-comment to output all keys to stats.txt
|
||||
FILE *fout;
|
||||
if ((fout = fopen("stats.txt","ab")) == NULL) {
|
||||
PrintAndLog("Could not create file name stats.txt");
|
||||
return 1;
|
||||
}
|
||||
fprintf(fout, "moebius,%d,%08x,%d,%s,%04x%08x,%0.Lf\r\n", counter, data.cuid, data.sector, (data.keytype) ? "B" : "A", (uint32_t) (outkey>>32),(uint32_t)(outkey&0xFFFFFFFF),(long double)t1);
|
||||
fclose(fout);
|
||||
*/
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
int tryMfk64_ex(uint8_t *data, uint64_t *outputkey){
|
||||
uint32_t uid = le32toh(data);
|
||||
uint32_t nt = le32toh(data+4); // tag challenge
|
||||
uint32_t nr_enc = le32toh(data+8); // encrypted reader challenge
|
||||
uint32_t ar_enc = le32toh(data+12); // encrypted reader response
|
||||
uint32_t at_enc = le32toh(data+16); // encrypted tag response
|
||||
return tryMfk64(uid, nt, nr_enc, ar_enc, at_enc, outputkey);
|
||||
}
|
||||
|
||||
int tryMfk64(uint32_t uid, uint32_t nt, uint32_t nr_enc, uint32_t ar_enc, uint32_t at_enc, 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
|
||||
struct Crypto1State *revstate;
|
||||
|
||||
PrintAndLog("Enter mfkey64");
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
// Extract the keystream from the messages
|
||||
ks2 = ar_enc ^ prng_successor(nt, 64);
|
||||
ks3 = at_enc ^ prng_successor(nt, 96);
|
||||
revstate = lfsr_recovery64(ks2, ks3);
|
||||
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);
|
||||
PrintAndLog("Found Key: [%012" PRIx64 "]", key);
|
||||
crypto1_destroy(revstate);
|
||||
*outputkey = key;
|
||||
|
||||
t1 = msclock() - t1;
|
||||
if ( t1 > 0 ) PrintAndLog("Time in mfkey64: %.1f seconds \n", (float)t1/1000.0);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
// Some lua scripting glue to proxmark core.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "scripting.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
|
@ -15,9 +17,8 @@
|
|||
#include "proxmark3.h"
|
||||
#include "usb_cmd.h"
|
||||
#include "cmdmain.h"
|
||||
#include "scripting.h"
|
||||
#include "util.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "mifarehost.h"
|
||||
#include "../common/iso15693tools.h"
|
||||
#include "iso14443crc.h"
|
||||
#include "../common/crc16.h"
|
||||
|
@ -125,49 +126,27 @@ 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){
|
||||
|
||||
uint64_t key;
|
||||
|
||||
int retval = mfDarkside(&key);
|
||||
|
||||
//Push the retval on the stack
|
||||
lua_pushinteger(L,retval);
|
||||
lua_pushinteger(L, retval);
|
||||
|
||||
//Push the key onto the stack
|
||||
uint8_t dest_key[8];
|
||||
num_to_bytes(key,sizeof(dest_key),dest_key);
|
||||
num_to_bytes(key, sizeof(dest_key), dest_key);
|
||||
|
||||
//printf("Pushing to lua stack: %012" PRIx64 "\n",key);
|
||||
lua_pushlstring(L,(const char *) dest_key,sizeof(dest_key));
|
||||
lua_pushlstring(L,(const char *)dest_key, sizeof(dest_key));
|
||||
|
||||
return 2; //Two return values
|
||||
}
|
||||
|
||||
//static int l_PrintAndLog(lua_State *L){ return CmdHF14AMfDump(luaL_checkstring(L, 1));}
|
||||
|
||||
static int l_clearCommandBuffer(lua_State *L){
|
||||
clearCommandBuffer();
|
||||
return 0;
|
||||
|
@ -499,7 +478,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},
|
||||
|
|
|
@ -8,7 +8,7 @@ author = "Martin Holst Swende"
|
|||
|
||||
desc =
|
||||
[[
|
||||
This is a which automates cracking and dumping mifare classic cards. It sets itself into
|
||||
This is a script which automates cracking and dumping mifare classic cards. It sets itself into
|
||||
'listening'-mode, after which it cracks and dumps any mifare classic card that you
|
||||
place by the device.
|
||||
|
||||
|
@ -63,91 +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}
|
||||
|
||||
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}
|
||||
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
|
||||
|
@ -209,8 +124,15 @@ function main(args)
|
|||
print("Card found, commencing crack", 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
|
||||
|
|
|
@ -465,18 +465,9 @@ uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
|
|||
*/
|
||||
static struct Crypto1State*
|
||||
check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
|
||||
uint32_t odd, uint32_t even, struct Crypto1State* sl)
|
||||
uint32_t odd, uint32_t even, struct Crypto1State* sl, uint32_t no_par)
|
||||
{
|
||||
uint32_t ks1, nr, ks2, rr, ks3, c, good = 1, no_par = 1;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (parities[i][j] != 0) {
|
||||
no_par = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
|
||||
|
||||
for(c = 0; good && c < 8; ++c) {
|
||||
sl->odd = odd ^ fastfwd[1][c];
|
||||
|
@ -510,7 +501,7 @@ check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
|
|||
* Implentation of the common prefix attack.
|
||||
*/
|
||||
struct Crypto1State*
|
||||
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8])
|
||||
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par)
|
||||
{
|
||||
struct Crypto1State *statelist, *s;
|
||||
uint32_t *odd, *even, *o, *e, top;
|
||||
|
@ -518,7 +509,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8])
|
|||
odd = lfsr_prefix_ks(ks, 1);
|
||||
even = lfsr_prefix_ks(ks, 0);
|
||||
|
||||
s = statelist = malloc((sizeof *statelist) << 20);
|
||||
s = statelist = malloc((sizeof *statelist) << 22); // was << 20. Need more for no_par special attack. Enough???
|
||||
if(!s || !odd || !even) {
|
||||
free(statelist);
|
||||
statelist = 0;
|
||||
|
@ -530,7 +521,7 @@ lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8])
|
|||
for(top = 0; top < 64; ++top) {
|
||||
*o += 1 << 21;
|
||||
*e += (!(top & 7) + 1) << 21;
|
||||
s = check_pfx_parity(pfx, rr, par, *o, *e, s);
|
||||
s = check_pfx_parity(pfx, rr, par, *o, *e, s, no_par);
|
||||
}
|
||||
|
||||
s->odd = s->even = 0;
|
||||
|
|
|
@ -41,7 +41,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
|
|||
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
||||
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
|
||||
struct Crypto1State*
|
||||
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
|
||||
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par);
|
||||
|
||||
|
||||
uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
|
||||
|
|
2254
common/lfdemod.c
2254
common/lfdemod.c
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,7 @@
|
|||
//generic
|
||||
extern size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType);
|
||||
extern int askdemod(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType);
|
||||
extern int askdemod_ext(uint8_t *BinStream, size_t *size, int *clk, int *invert, int maxErr, uint8_t amp, uint8_t askType, int *startIdx);
|
||||
extern void askAmp(uint8_t *BitStream, size_t size);
|
||||
extern int BiphaseRawDecode(uint8_t * BitStream, size_t *size, int offset, int invert);
|
||||
extern uint32_t bytebits_to_byte(uint8_t* src, size_t numbits);
|
||||
|
@ -28,23 +29,24 @@ extern int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxE
|
|||
extern uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low);
|
||||
extern uint8_t detectFSKClk(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow);
|
||||
extern uint8_t detectFSKClk_ext(uint8_t *BitStream, size_t size, uint8_t fcHigh, uint8_t fcLow, int *firstClockEdge);
|
||||
extern int DetectNRZClock(uint8_t dest[], size_t size, int clock);
|
||||
extern int DetectNRZClock_ext(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx);
|
||||
extern int DetectNRZClock(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx);
|
||||
extern int DetectPSKClock(uint8_t dest[], size_t size, int clock);
|
||||
extern int DetectPSKClock_ext(uint8_t dest[], size_t size, int clock, int *firstPhaseShift);
|
||||
extern int DetectStrongAskClock(uint8_t dest[], size_t size, uint8_t high, uint8_t low, int *clock);
|
||||
extern int DetectStrongAskClock(uint8_t dest[], size_t size, int high, int low, int *clock);
|
||||
extern bool DetectST(uint8_t buffer[], size_t *size, int *foundclock);
|
||||
extern bool DetectST_ext(uint8_t buffer[], size_t *size, int *foundclock, size_t *ststart, size_t *stend);
|
||||
extern int fskdemod(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow);
|
||||
extern int fskdemod_ext(uint8_t *dest, size_t size, uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, int *startIdx);
|
||||
extern int getHiLo(uint8_t *BitStream, size_t size, int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo);
|
||||
extern uint32_t manchesterEncode2Bytes(uint16_t datain);
|
||||
extern int ManchesterEncode(uint8_t *BitStream, size_t size);
|
||||
extern int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert);
|
||||
extern int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert);
|
||||
extern int manrawdecode(uint8_t *BitStream, size_t *size, uint8_t invert, uint8_t *alignPos);
|
||||
extern int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert, int *startIdx);
|
||||
extern uint8_t parityTest(uint32_t bits, uint8_t bitLen, uint8_t pType);
|
||||
extern uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx);
|
||||
extern bool preambleSearchEx(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx, bool findone);
|
||||
extern int pskRawDemod(uint8_t dest[], size_t *size, int *clock, int *invert);
|
||||
extern int pskRawDemod_ext(uint8_t dest[], size_t *size, int *clock, int *invert, int *startIdx);
|
||||
extern void psk2TOpsk1(uint8_t *BitStream, size_t size);
|
||||
extern void psk1TOpsk2(uint8_t *BitStream, size_t size);
|
||||
extern size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen);
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
VPATH = ../../common/crapto1
|
||||
CC = gcc
|
||||
LD = gcc
|
||||
CFLAGS = -I../../common -Wall -O4
|
||||
LDFLAGS =
|
||||
|
||||
OBJS = crypto1.o crapto1.o
|
||||
HEADERS = crapto1.h
|
||||
EXES = nonce2key
|
||||
WINEXES = $(patsubst %, %.exe, $(EXES))
|
||||
|
||||
all: $(OBJS) $(EXES)
|
||||
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
% : %.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(EXES) $(WINEXES)
|
|
@ -1,57 +0,0 @@
|
|||
#include "crapto1/crapto1.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
typedef unsigned char byte_t;
|
||||
|
||||
int main(const int argc, const char* argv[]) {
|
||||
struct Crypto1State *state;
|
||||
uint32_t pos, uid, nt, nr, rr, nr_diff;
|
||||
byte_t bt, i, ks3x[8], par[8][8];
|
||||
uint64_t key_recovered;
|
||||
uint64_t par_info;
|
||||
uint64_t ks_info;
|
||||
nr = rr = 0;
|
||||
|
||||
if (argc < 5) {
|
||||
printf("\nsyntax: %s <uid> <nt> <par> <ks>\n\n",argv[0]);
|
||||
return 1;
|
||||
}
|
||||
sscanf(argv[1],"%08x",&uid);
|
||||
sscanf(argv[2],"%08x",&nt);
|
||||
sscanf(argv[3],"%016" SCNx64,&par_info);
|
||||
sscanf(argv[4],"%016" SCNx64,&ks_info);
|
||||
|
||||
// Reset the last three significant bits of the reader nonce
|
||||
nr &= 0xffffff1f;
|
||||
|
||||
printf("\nuid(%08x) nt(%08x) par(%016" PRIx64 ") ks(%016" PRIx64 ")\n\n",uid,nt,par_info,ks_info);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
printf("|diff|{nr} |ks3|ks3^5|parity |\n");
|
||||
printf("+----+--------+---+-----+---------------+\n");
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
nr_diff = nr | i << 5;
|
||||
printf("| %02x |%08x|",i << 5, nr_diff);
|
||||
printf(" %01x | %01x |",ks3x[i], ks3x[i]^5);
|
||||
for (pos=0; pos<7; pos++) printf("%01x,",par[i][pos]);
|
||||
printf("%01x|\n",par[i][7]);
|
||||
}
|
||||
|
||||
state = lfsr_common_prefix(nr,rr,ks3x,par);
|
||||
lfsr_rollback_word(state,uid^nt,0);
|
||||
crypto1_get_lfsr(state,&key_recovered);
|
||||
printf("\nkey recovered: %012" PRIx64 "\n\n",key_recovered);
|
||||
crypto1_destroy(state);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue