move mifare stuff to its folder

This commit is contained in:
merlokk 2019-02-21 19:15:46 +02:00
commit 3b21b17509
19 changed files with 1158 additions and 1147 deletions

173
client/mifare/mfkey.c Normal file
View file

@ -0,0 +1,173 @@
//-----------------------------------------------------------------------------
// 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 "mfkey.h"
// MIFARE
int compare_uint64(const void *a, const void *b) {
if (*(uint64_t*)b == *(uint64_t*)a) return 0;
if (*(uint64_t*)b < *(uint64_t*)a) return 1;
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.
uint32_t intersection(uint64_t *listA, uint64_t *listB) {
if (listA == NULL || listB == NULL)
return 0;
uint64_t *p1, *p2, *p3;
p1 = p3 = listA;
p2 = listB;
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 - listA;
}
// Darkside attack (hf mf mifare)
// if successful it will return a list of keys, not just one.
uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) {
struct Crypto1State *states;
uint32_t i, pos;
uint8_t bt, ks3x[8], par[8][8];
uint64_t key_recovered;
uint64_t *keylist;
// 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;
par[7-pos][0] = (bt >> 0) & 1;
par[7-pos][1] = (bt >> 1) & 1;
par[7-pos][2] = (bt >> 2) & 1;
par[7-pos][3] = (bt >> 3) & 1;
par[7-pos][4] = (bt >> 4) & 1;
par[7-pos][5] = (bt >> 5) & 1;
par[7-pos][6] = (bt >> 6) & 1;
par[7-pos][7] = (bt >> 7) & 1;
}
states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0));
if (!states) {
*keys = NULL;
return 0;
}
keylist = (uint64_t*)states;
for (i = 0; keylist[i]; i++) {
lfsr_rollback_word(states+i, uid ^ nt, 0);
crypto1_get_lfsr(states+i, &key_recovered);
keylist[i] = key_recovered;
}
keylist[i] = -1;
*keys = keylist;
return i;
}
// 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;
uint32_t p640 = prng_successor(data.nonce, 64);
uint32_t p641 = prng_successor(data.nonce2, 64);
s = lfsr_recovery32(data.ar ^ p640, 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) ^ p641)) {
outkey = key;
counter++;
if (counter == 20) break;
}
}
isSuccess = (counter == 1);
*outputkey = ( isSuccess ) ? outkey : 0;
crypto1_destroy(s);
return isSuccess;
}
// recover key from 2 reader responses on 2 different tag challenges
// skip "several found keys". Only return true if ONE key is found
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;
uint32_t p640 = prng_successor(data.nonce, 64);
uint32_t p641 = prng_successor(data.nonce2, 64);
s = lfsr_recovery32(data.ar ^ p640, 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) ^ p641)) {
outkey = key;
++counter;
if (counter == 20) break;
}
}
isSuccess = (counter == 1);
*outputkey = ( isSuccess ) ? outkey : 0;
crypto1_destroy(s);
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;
// 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);
crypto1_destroy(revstate);
*outputkey = key;
return 0;
}

30
client/mifare/mfkey.h Normal file
View file

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
#ifndef MFKEY_H
#define MFKEY_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "mifare.h"
#include "crapto1/crapto1.h"
extern uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys);
extern bool mfkey32(nonces_t data, uint64_t *outputkey);
extern bool mfkey32_moebius(nonces_t data, uint64_t *outputkey);
extern int mfkey64(nonces_t data, uint64_t *outputkey);
extern int compare_uint64(const void *a, const void *b);
extern uint32_t intersection(uint64_t *listA, uint64_t *listB);
#endif

311
client/mifare/mifare4.c Normal file
View file

@ -0,0 +1,311 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
// Copyright (C) 2018 drHatson
//
// 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.
//-----------------------------------------------------------------------------
// iso14443-4 mifare commands
//-----------------------------------------------------------------------------
#include "mifare4.h"
#include <ctype.h>
#include <string.h>
#include "cmdhf14a.h"
#include "util.h"
#include "ui.h"
#include "crypto/libpcrypto.h"
AccessConditions_t MFAccessConditions[] = {
{0x00, "rdAB wrAB incAB dectrAB"},
{0x01, "rdAB dectrAB"},
{0x02, "rdAB"},
{0x03, "rdB wrB"},
{0x04, "rdAB wrB"},
{0x05, "rdB"},
{0x06, "rdAB wrB incB dectrAB"},
{0x07, "none"}
};
AccessConditions_t MFAccessConditionsTrailer[] = {
{0x00, "rdAbyA rdCbyA rdBbyA wrBbyA"},
{0x01, "wrAbyA rdCbyA wrCbyA rdBbyA wrBbyA"},
{0x02, "rdCbyA rdBbyA"},
{0x03, "wrAbyB rdCbyAB wrCbyB wrBbyB"},
{0x04, "wrAbyB rdCbyAB wrBbyB"},
{0x05, "rdCbyAB wrCbyB"},
{0x06, "rdCbyAB"},
{0x07, "rdCbyAB"}
};
char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) {
static char StaticNone[] = "none";
uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn;
uint8_t data2 = ((data[2]) & 0x0f) >> blockn;
uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn;
uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01);
if (blockn == 3) {
for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)
if (MFAccessConditionsTrailer[i].cond == cond) {
return MFAccessConditionsTrailer[i].description;
}
} else {
for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++)
if (MFAccessConditions[i].cond == cond) {
return MFAccessConditions[i].description;
}
};
return StaticNone;
};
int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) {
memcpy(&iv[0], session->TI, 4);
memcpy(&iv[4], &session->R_Ctr, 2);
memcpy(&iv[6], &session->W_Ctr, 2);
memcpy(&iv[8], &session->R_Ctr, 2);
memcpy(&iv[10], &session->W_Ctr, 2);
memcpy(&iv[12], &session->R_Ctr, 2);
memcpy(&iv[14], &session->W_Ctr, 2);
return 0;
}
int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) {
memcpy(&iv[0], &session->R_Ctr, 2);
memcpy(&iv[2], &session->W_Ctr, 2);
memcpy(&iv[4], &session->R_Ctr, 2);
memcpy(&iv[6], &session->W_Ctr, 2);
memcpy(&iv[8], &session->R_Ctr, 2);
memcpy(&iv[10], &session->W_Ctr, 2);
memcpy(&iv[12], session->TI, 4);
return 0;
}
int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) {
if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1)
return 1;
memset(mac, 0x00, 8);
uint16_t ctr = session->R_Ctr;
switch(mtype) {
case mtypWriteCmd:
case mtypWriteResp:
ctr = session->W_Ctr;
break;
case mtypReadCmd:
case mtypReadResp:
break;
}
uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0};
int macdatalen = datalen;
memcpy(&macdata[3], session->TI, 4);
switch(mtype) {
case mtypReadCmd:
memcpy(&macdata[7], &data[1], datalen - 1);
macdatalen = datalen + 6;
break;
case mtypReadResp:
macdata[7] = blockNum;
macdata[8] = 0;
macdata[9] = blockCount;
memcpy(&macdata[10], &data[1], datalen - 1);
macdatalen = datalen + 9;
break;
case mtypWriteCmd:
memcpy(&macdata[7], &data[1], datalen - 1);
macdatalen = datalen + 6;
break;
case mtypWriteResp:
macdatalen = 1 + 6;
break;
}
if (verbose)
PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen));
return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen);
}
int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) {
uint8_t data[257] = {0};
int datalen = 0;
uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};
uint8_t RndB[17] = {0};
if (session)
session->Authenticated = false;
uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen);
if (res) {
PrintAndLogEx(ERR, "Exchande raw error: %d", res);
DropField();
return 2;
}
if (verbose)
PrintAndLogEx(INFO, "<phase1: %s", sprint_hex(data, datalen));
if (datalen < 1) {
PrintAndLogEx(ERR, "Card response wrong length: %d", datalen);
DropField();
return 3;
}
if (data[0] != 0x90) {
PrintAndLogEx(ERR, "Card response error: %02x", data[2]);
DropField();
return 3;
}
if (datalen != 19) { // code 1b + 16b + crc 2b
PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen);
DropField();
return 3;
}
aes_decode(NULL, key, &data[1], RndB, 16);
RndB[16] = RndB[0];
if (verbose)
PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16));
uint8_t cmd2[33] = {0};
cmd2[0] = 0x72;
uint8_t raw[32] = {0};
memmove(raw, RndA, 16);
memmove(&raw[16], &RndB[1], 16);
aes_encode(NULL, key, raw, &cmd2[1], 32);
if (verbose)
PrintAndLogEx(INFO, ">phase2: %s", sprint_hex(cmd2, 33));
res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen);
if (res) {
PrintAndLogEx(ERR, "Exchande raw error: %d", res);
DropField();
return 4;
}
if (verbose)
PrintAndLogEx(INFO, "<phase2: %s", sprint_hex(data, datalen));
aes_decode(NULL, key, &data[1], raw, 32);
if (verbose) {
PrintAndLogEx(INFO, "res: %s", sprint_hex(raw, 32));
PrintAndLogEx(INFO, "RndA`: %s", sprint_hex(&raw[4], 16));
}
if (memcmp(&raw[4], &RndA[1], 16)) {
PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal");
if (verbose) {
PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16));
PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16));
}
DropField();
return 5;
}
if (verbose) {
PrintAndLogEx(INFO, " TI: %s", sprint_hex(raw, 4));
PrintAndLogEx(INFO, "pic: %s", sprint_hex(&raw[20], 6));
PrintAndLogEx(INFO, "pcd: %s", sprint_hex(&raw[26], 6));
}
uint8_t kenc[16] = {0};
memcpy(&kenc[0], &RndA[11], 5);
memcpy(&kenc[5], &RndB[11], 5);
for(int i = 0; i < 5; i++)
kenc[10 + i] = RndA[4 + i] ^ RndB[4 + i];
kenc[15] = 0x11;
aes_encode(NULL, key, kenc, kenc, 16);
if (verbose) {
PrintAndLogEx(INFO, "kenc: %s", sprint_hex(kenc, 16));
}
uint8_t kmac[16] = {0};
memcpy(&kmac[0], &RndA[7], 5);
memcpy(&kmac[5], &RndB[7], 5);
for(int i = 0; i < 5; i++)
kmac[10 + i] = RndA[0 + i] ^ RndB[0 + i];
kmac[15] = 0x22;
aes_encode(NULL, key, kmac, kmac, 16);
if (verbose) {
PrintAndLogEx(INFO, "kmac: %s", sprint_hex(kmac, 16));
}
if (!leaveSignalON)
DropField();
if (verbose)
PrintAndLog("");
if (session) {
session->Authenticated = true;
session->R_Ctr = 0;
session->W_Ctr = 0;
session->KeyNum = keyn[1] + (keyn[0] << 8);
memmove(session->RndA, RndA, 16);
memmove(session->RndB, RndB, 16);
memmove(session->Key, key, 16);
memmove(session->TI, raw, 4);
memmove(session->PICCap2, &raw[20], 6);
memmove(session->PCDCap2, &raw[26], 6);
memmove(session->Kenc, kenc, 16);
memmove(session->Kmac, kmac, 16);
}
PrintAndLogEx(INFO, "Authentication OK");
return 0;
}
// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards),
// plus evtl. 8 sectors with 16 blocks each (4k cards)
uint8_t mfNumBlocksPerSector(uint8_t sectorNo) {
if (sectorNo < 32)
return 4;
else
return 16;
}
uint8_t mfFirstBlockOfSector(uint8_t sectorNo) {
if (sectorNo < 32)
return sectorNo * 4;
else
return 32 * 4 + (sectorNo - 32) * 16;
}
uint8_t mfSectorTrailer(uint8_t blockNo) {
if (blockNo < 32*4) {
return (blockNo | 0x03);
} else {
return (blockNo | 0x0f);
}
}
bool mfIsSectorTrailer(uint8_t blockNo) {
return (blockNo == mfSectorTrailer(blockNo));
}
uint8_t mfSectorNum(uint8_t blockNo) {
if (blockNo < 32 * 4)
return blockNo / 4;
else
return 32 + (blockNo - 32 * 4) / 16;
}

58
client/mifare/mifare4.h Normal file
View file

@ -0,0 +1,58 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
// Copyright (C) 2018 drHatson
//
// 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.
//-----------------------------------------------------------------------------
// iso14443-4 mifare commands
//-----------------------------------------------------------------------------
#ifndef MIFARE4_H
#define MIFARE4_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct {
bool Authenticated;
uint8_t Key[16];
uint16_t KeyNum;
uint8_t RndA[16];
uint8_t RndB[16];
uint8_t TI[4];
uint8_t PICCap2[6];
uint8_t PCDCap2[6];
uint8_t Kenc[16];
uint8_t Kmac[16];
uint16_t R_Ctr;
uint16_t W_Ctr;
}mf4Session;
typedef enum {
mtypReadCmd,
mtypReadResp,
mtypWriteCmd,
mtypWriteResp,
} MACType_t;
typedef struct {
uint8_t cond;
char *description;
} AccessConditions_t;
extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose);
extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data);
extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
extern uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
extern uint8_t mfSectorTrailer(uint8_t blockNo);
extern bool mfIsSectorTrailer(uint8_t blockNo);
extern uint8_t mfSectorNum(uint8_t blockNo);
#endif // mifare4.h

View file

@ -0,0 +1,48 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2017 Merlok
//
// 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 default constants
//-----------------------------------------------------------------------------
#ifndef MIFAREDEFAULT_H__
#define MIFAREDEFAULT_H__
#include <inttypes.h>
#define MIFARE_DEFAULTKEYS_SIZE sizeof(g_mifare_default_keys) / sizeof(uint64_t)
static const uint64_t g_mifare_default_keys[] =
{
0xffffffffffff, // Default key (first key used by program if no user defined key)
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key
0xb0b1b2b3b4b5,
0xc0c1c2c3c4c5,
0xd0d1d2d3d4d5,
0xaabbccddeeff,
0x1a2b3c4d5e6f,
0x123456789abc,
0x010203040506,
0x123456abcdef,
0xabcdef123456,
0x4d3a99c351dd,
0x1a982c7e459a,
0xd3f7d3f7d3f7, // NDEF public key
0x714c5c886e97,
0x587ee5f9350f,
0xa0478cc39091,
0x533cb6c723f6,
0x8fd0a4f256e9,
0x0000014b5c31,
0xb578f38a5c61,
0x96a301bce267
};
static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5};
static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7};
#endif

1015
client/mifare/mifarehost.c Normal file

File diff suppressed because it is too large Load diff

103
client/mifare/mifarehost.h Normal file
View file

@ -0,0 +1,103 @@
// Merlok, 2011
// people from mifare@nethemba.com, 2010
//
// 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.
//-----------------------------------------------------------------------------
// High frequency ISO14443A commands
//-----------------------------------------------------------------------------
#ifndef __MIFARE_HOST_H
#define __MIFARE_HOST_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "proxmark3.h" // time_t
#include "common.h"
#include "util.h" // FILE_PATH_SIZE
#include "ui.h" // PrintAndLog...
#include "crapto1/crapto1.h"
#include "crc16.h"
#include "protocols.h"
#include "mifare.h"
#include "mfkey.h"
#include "util_posix.h" // msclock
#define MIFARE_SECTOR_RETRY 10
// mifare tracer flags
#define TRACE_IDLE 0x00
#define TRACE_AUTH1 0x01
#define TRACE_AUTH2 0x02
#define TRACE_AUTH_OK 0x03
#define TRACE_READ_DATA 0x04
#define TRACE_WRITE_OK 0x05
#define TRACE_WRITE_DATA 0x06
#define TRACE_ERROR 0xFF
typedef struct {
union {
struct Crypto1State *slhead;
uint64_t *keyhead;
} head;
union {
struct Crypto1State *sltail;
uint64_t *keytail;
} tail;
uint32_t len;
uint32_t uid;
uint32_t blockNo;
uint32_t keyType;
uint32_t nt;
uint32_t ks1;
} StateList_t;
typedef struct {
uint64_t Key[2];
uint8_t foundKey[2];
} sector_t;
typedef struct {
uint8_t keyA[6];
uint8_t keyB[6];
//uint8_t foundKey[2];
} icesector_t;
extern char logHexFileName[FILE_PATH_SIZE];
extern int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key);
extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys, bool calibrate);
extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key);
extern int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory);
extern int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
extern int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data);
extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
extern int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard);
extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
extern int mfTraceInit(uint8_t *tuid, uint8_t uidlen, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile);
extern int mfTraceDecode(uint8_t *data_src, int len, bool wantSaveToEmlFile);
extern int isTraceCardEmpty(void);
extern int isBlockEmpty(int blockN);
extern int isBlockTrailer(int blockN);
extern int loadTraceCard(uint8_t *tuid, uint8_t uidlen);
extern int saveTraceCard(void);
extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
extern int detect_classic_prng(void);
extern int detect_classic_nackbug(bool verbose);
extern void detect_classic_magic(void);
extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted);
#endif