mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-20 03:48:33 +08:00
Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3
This commit is contained in:
commit
11f86c2d95
24 changed files with 1663 additions and 1223 deletions
|
@ -102,6 +102,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added `hf emv` `gpo`, `readrec`, `genac`, `challenge`, `intauth` - separate commands from `hf emc exec` (@merlokk)
|
||||
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk)
|
||||
- Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk)
|
||||
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
|
||||
|
||||
### Fixed
|
||||
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
|
||||
|
|
|
@ -108,7 +108,7 @@ CORESRCS = uart_posix.c \
|
|||
|
||||
CMDSRCS = crapto1/crapto1.c \
|
||||
crapto1/crypto1.c \
|
||||
mfkey.c \
|
||||
mifare/mfkey.c \
|
||||
tea.c \
|
||||
fido/additional_ca.c \
|
||||
fido/cose.c \
|
||||
|
@ -126,7 +126,7 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
loclass/elite_crack.c \
|
||||
loclass/fileutils.c \
|
||||
whereami.c \
|
||||
mifarehost.c \
|
||||
mifare/mifarehost.c \
|
||||
parity.c \
|
||||
crc.c \
|
||||
crc16.c \
|
||||
|
@ -156,7 +156,8 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
emv/test/cda_test.c\
|
||||
emv/cmdemv.c \
|
||||
emv/emv_roca.c \
|
||||
mifare4.c \
|
||||
mifare/mifare4.c \
|
||||
mifare/mad.c \
|
||||
cmdanalyse.c \
|
||||
cmdhf.c \
|
||||
cmdhflist.c \
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "tea.h"
|
||||
#include "legic_prng.h"
|
||||
#include "loclass/elite_crack.h"
|
||||
#include "mfkey.h" //nonce2key
|
||||
#include "mifare/mfkey.h" //nonce2key
|
||||
#include "util_posix.h" // msclock
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "cmdhfmf.h"
|
||||
#include "cmdhfmfu.h"
|
||||
#include "cmdhf.h" // list cmd
|
||||
#include "mifarehost.h"
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "emv/apduinfo.h"
|
||||
#include "emv/emvcore.h"
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
#include "emv/cmdemv.h" // EMV
|
||||
#include "protocols.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "mifarehost.h"
|
||||
#include "mifaredefault.h"
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "mifare/mifaredefault.h"
|
||||
#include "parity.h" // oddparity
|
||||
#include "iso15693tools.h" // ISO15693 crc
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhfmf.h"
|
||||
#include "mifare4.h"
|
||||
#include "mifare/mifare4.h"
|
||||
#include "mifare/mad.h"
|
||||
|
||||
|
||||
#define MFBLOCK_SIZE 16
|
||||
|
@ -3213,6 +3214,49 @@ int CmdHF14AMfAuth4(const char *Cmd) {
|
|||
return MifareAuth4(NULL, keyn, key, true, false, true);
|
||||
}
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
|
||||
int CmdHF14AMfMAD(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf mf mad",
|
||||
"Checks and prints Mifare Application Directory (MAD)",
|
||||
"Usage:\n\thf mf mad -> shows MAD if exists\n");
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("vV", "verbose", "show technical data"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
bool verbose = arg_get_lit(1);
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
uint8_t sector[16 * 4] = {0};
|
||||
if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector)) {
|
||||
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for(int i = 0; i < 4; i ++)
|
||||
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or[i * 16], 16));
|
||||
}
|
||||
|
||||
bool haveMAD2 = false;
|
||||
MAD1DecodeAndPrint(sector, verbose, &haveMAD2);
|
||||
|
||||
if (haveMAD2) {
|
||||
if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector)) {
|
||||
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
MAD2DecodeAndPrint(sector, verbose);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHF14AMfList(const char *Cmd) {
|
||||
CmdTraceList("mf");
|
||||
return 0;
|
||||
|
@ -3255,6 +3299,9 @@ static command_t CommandTable[] = {
|
|||
{"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"},
|
||||
{"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"},
|
||||
{"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"},
|
||||
{"-----------", CmdHelp, 1, ""},
|
||||
{"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"},
|
||||
// {"ndef", CmdHF14AMfHDEF, 0, "Checks and prints NDEF records from card"},
|
||||
|
||||
{"ice", CmdHF14AMfice, 0, "collect Mifare Classic nonces to file"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "mifare.h" // nonces_t struct
|
||||
#include "mfkey.h" // mfkey32_moebious
|
||||
#include "mifare/mfkey.h" // mfkey32_moebious
|
||||
#include "cmdhfmfhard.h"
|
||||
#include "mifarehost.h" // icesector_t, sector_t
|
||||
#include "mifare/mifarehost.h" // icesector_t, sector_t
|
||||
#include "util_posix.h" // msclock
|
||||
#include "mifaredefault.h" // mifare default key array
|
||||
#include "mifare/mifaredefault.h" // mifare default key array
|
||||
#include "cmdhf14a.h" // dropfield
|
||||
#include "cliparser/cliparser.h" // argtable
|
||||
#include "hardnested/hardnested_bf_core.h" // SetSIMDInstr
|
||||
|
|
|
@ -22,109 +22,15 @@
|
|||
#include "ui.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "mifare.h"
|
||||
#include "mifare4.h"
|
||||
#include "mifare/mifare4.h"
|
||||
#include "mifare/mad.h"
|
||||
#include "cliparser/cliparser.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
typedef struct {
|
||||
uint8_t Code;
|
||||
const char *Description;
|
||||
} PlusErrorsElm;
|
||||
|
||||
static const PlusErrorsElm PlusErrors[] = {
|
||||
{0xFF, ""},
|
||||
{0x00, "Transfer cannot be granted within the current authentication."},
|
||||
{0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."},
|
||||
{0x07, "Too many read or write commands in the session or in the transaction."},
|
||||
{0x08, "Invalid MAC in command or response"},
|
||||
{0x09, "Block Number is not valid"},
|
||||
{0x0a, "Invalid block number, not existing block number"},
|
||||
{0x0b, "The current command code not available at the current card state."},
|
||||
{0x0c, "Length error"},
|
||||
{0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."},
|
||||
{0x90, "OK"},
|
||||
};
|
||||
int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
|
||||
|
||||
const char * GetErrorDescription(uint8_t errorCode) {
|
||||
for(int i = 0; i < PlusErrorsLen; i++)
|
||||
if (errorCode == PlusErrors[i].Code)
|
||||
return PlusErrors[i].Description;
|
||||
|
||||
return PlusErrors[0].Description;
|
||||
}
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static bool VerboseMode = false;
|
||||
void SetVerboseMode(bool verbose) {
|
||||
VerboseMode = verbose;
|
||||
}
|
||||
|
||||
int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
||||
|
||||
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
|
||||
memmove(&rcmd[3], key, 16);
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[1] = {0xaa};
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount};
|
||||
if (!plain && session)
|
||||
CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->R_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
|
||||
memmove(&rcmd[3], data, 16);
|
||||
if (session)
|
||||
CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->W_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHFMFPInfo(const char *cmd) {
|
||||
|
||||
if (cmd && strlen(cmd) > 0)
|
||||
|
@ -229,7 +135,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
|
|||
CLIGetHexWithReturn(3, key, &keyLen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keyLen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
@ -260,7 +166,7 @@ int CmdHFMFPWritePerso(const char *cmd) {
|
|||
}
|
||||
|
||||
if (data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Write OK.");
|
||||
|
@ -304,7 +210,7 @@ int CmdHFMFPInitPerso(const char *cmd) {
|
|||
if (!keyLen)
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
||||
SetVerboseMode(verbose2);
|
||||
mfpSetVerboseMode(verbose2);
|
||||
for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
|
||||
keyNum[0] = sn >> 8;
|
||||
keyNum[1] = sn & 0xff;
|
||||
|
@ -319,7 +225,7 @@ int CmdHFMFPInitPerso(const char *cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
|
||||
keyNum[0] = CardAddresses[i] >> 8;
|
||||
keyNum[1] = CardAddresses[i] & 0xff;
|
||||
|
@ -360,7 +266,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
|
|||
bool verbose = arg_get_lit(1);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
uint8_t data[250] = {0};
|
||||
int datalen = 0;
|
||||
|
@ -377,7 +283,7 @@ int CmdHFMFPCommitPerso(const char *cmd) {
|
|||
}
|
||||
|
||||
if (data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 1;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Switch level OK.");
|
||||
|
@ -453,7 +359,7 @@ int CmdHFMFPRdbl(const char *cmd) {
|
|||
CLIGetHexWithReturn(6, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
@ -504,7 +410,7 @@ int CmdHFMFPRdbl(const char *cmd) {
|
|||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
@ -563,7 +469,7 @@ int CmdHFMFPRdsc(const char *cmd) {
|
|||
CLIGetHexWithReturn(5, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
@ -605,7 +511,7 @@ int CmdHFMFPRdsc(const char *cmd) {
|
|||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
DropField();
|
||||
return 6;
|
||||
}
|
||||
|
@ -661,7 +567,7 @@ int CmdHFMFPWrbl(const char *cmd) {
|
|||
CLIGetHexWithReturn(5, key, &keylen);
|
||||
CLIParserFree();
|
||||
|
||||
SetVerboseMode(verbose);
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
|
@ -714,7 +620,7 @@ int CmdHFMFPWrbl(const char *cmd) {
|
|||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], GetErrorDescription(data[0]));
|
||||
PrintAndLogEx(ERR, "Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
DropField();
|
||||
return 6;
|
||||
}
|
||||
|
@ -733,6 +639,50 @@ int CmdHFMFPWrbl(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdHFMFPMAD(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf mfp mad",
|
||||
"Checks and prints Mifare Application Directory (MAD)",
|
||||
"Usage:\n\thf mfp mad -> shows MAD if exists\n");
|
||||
|
||||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("vV", "verbose", "show technical data"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
bool verbose = arg_get_lit(1);
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
uint8_t sector[16 * 4] = {0};
|
||||
if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
for(int i = 0; i < 4; i ++)
|
||||
PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or[i * 16], 16));
|
||||
}
|
||||
|
||||
bool haveMAD2 = false;
|
||||
MAD1DecodeAndPrint(sector, verbose, &haveMAD2);
|
||||
|
||||
if (haveMAD2) {
|
||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
MAD2DecodeAndPrint(sector, verbose);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
|
@ -744,6 +694,7 @@ static command_t CommandTable[] =
|
|||
{"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
|
||||
{"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
|
||||
{"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
|
||||
{"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#ifndef CMDHFMFP_H__
|
||||
#define CMDHFMFP_H__
|
||||
|
||||
#include "mifaredefault.h"
|
||||
#include "mifare/mifaredefault.h"
|
||||
|
||||
extern int CmdHFMFP(const char *Cmd);
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ fc00018778f7,--VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA
|
|||
314B49474956,--VIGIK1KeyA
|
||||
564c505f4d41,--VIGIK1KeyB
|
||||
ba5b895da162,--VIGIK1KeyB
|
||||
4143414F5250,
|
||||
#
|
||||
# Data from: http://irq5.io/2013/04/13/decoding-bcard-conference-badges/
|
||||
f4a9ef2afc6d,--BCARD KeyB
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#include <stdarg.h>
|
||||
#include "../ui.h"
|
||||
#include "../emv/emvjson.h"
|
||||
#include "mifare4.h"
|
||||
#include "mifare/mifare4.h"
|
||||
#include "cmdhfmfu.h"
|
||||
|
||||
typedef enum {
|
||||
|
|
212
client/mifare/mad.c
Normal file
212
client/mifare/mad.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2019 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 Application Directory (MAD) functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "mad.h"
|
||||
#include "ui.h"
|
||||
#include "crc.h"
|
||||
#include "util.h"
|
||||
|
||||
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
|
||||
static madAIDDescr madKnownAIDs[] = {
|
||||
{0x0000, "free"},
|
||||
{0x0001, "defect, e.g. access keys are destroyed or unknown"},
|
||||
{0x0002, "reserved"},
|
||||
{0x0003, "contains additional directory info"},
|
||||
{0x0004, "contains card holder information in ASCII format."},
|
||||
{0x0005, "not applicable (above memory size)"},
|
||||
|
||||
{0x03e1, "NDEF"},
|
||||
};
|
||||
|
||||
static madAIDDescr madKnownClusterCodes[] = {
|
||||
{0x00, "cluster: card administration"},
|
||||
{0x01, "cluster: miscellaneous applications"},
|
||||
{0x02, "cluster: miscellaneous applications"},
|
||||
{0x03, "cluster: miscellaneous applications"},
|
||||
{0x04, "cluster: miscellaneous applications"},
|
||||
{0x05, "cluster: miscellaneous applications"},
|
||||
{0x06, "cluster: miscellaneous applications"},
|
||||
{0x07, "cluster: miscellaneous applications"},
|
||||
{0x08, "cluster: airlines"},
|
||||
{0x09, "cluster: ferry traffic"},
|
||||
{0x10, "cluster: railway services"},
|
||||
{0x11, "cluster: miscellaneous applications"},
|
||||
{0x12, "cluster: transport"},
|
||||
{0x14, "cluster: security solutions"},
|
||||
{0x18, "cluster: city traffic"},
|
||||
{0x19, "cluster: Czech Railways"},
|
||||
{0x20, "cluster: bus services"},
|
||||
{0x21, "cluster: multi modal transit"},
|
||||
{0x28, "cluster: taxi"},
|
||||
{0x30, "cluster: road toll"},
|
||||
{0x31, "cluster: generic transport"},
|
||||
{0x38, "cluster: company services"},
|
||||
{0x40, "cluster: city card services"},
|
||||
{0x47, "cluster: access control & security"},
|
||||
{0x48, "cluster: access control & security"},
|
||||
{0x49, "cluster: VIGIK"},
|
||||
{0x4A, "cluster: Ministry of Defence, Netherlands"},
|
||||
{0x4B, "cluster: Bosch Telecom, Germany"},
|
||||
{0x4C, "cluster: European Union Institutions"},
|
||||
{0x50, "cluster: ski ticketing"},
|
||||
{0x51, "cluster: access control & security"},
|
||||
{0x52, "cluster: access control & security"},
|
||||
{0x53, "cluster: access control & security"},
|
||||
{0x54, "cluster: access control & security"},
|
||||
{0x55, "cluster: SOAA standard for offline access standard"},
|
||||
{0x56, "cluster: access control & security"},
|
||||
{0x58, "cluster: academic services"},
|
||||
{0x60, "cluster: food"},
|
||||
{0x68, "cluster: non-food trade"},
|
||||
{0x70, "cluster: hotel"},
|
||||
{0x71, "cluster: loyalty"},
|
||||
{0x75, "cluster: airport services"},
|
||||
{0x78, "cluster: car rental"},
|
||||
{0x79, "cluster: Dutch government"},
|
||||
{0x80, "cluster: administration services"},
|
||||
{0x88, "cluster: electronic purse"},
|
||||
{0x90, "cluster: television"},
|
||||
{0x91, "cluster: cruise ship"},
|
||||
{0x95, "cluster: IOPTA"},
|
||||
{0x97, "cluster: metering"},
|
||||
{0x98, "cluster: telephone"},
|
||||
{0xA0, "cluster: health services"},
|
||||
{0xA8, "cluster: warehouse"},
|
||||
{0xB0, "cluster: electronic trade"},
|
||||
{0xB8, "cluster: banking"},
|
||||
{0xC0, "cluster: entertainment & sports"},
|
||||
{0xC8, "cluster: car parking"},
|
||||
{0xC9, "cluster: fleet management"},
|
||||
{0xD0, "cluster: fuel, gasoline"},
|
||||
{0xD8, "cluster: info services"},
|
||||
{0xE0, "cluster: press"},
|
||||
{0xE1, "cluster: NFC Forum"},
|
||||
{0xE8, "cluster: computer"},
|
||||
{0xF0, "cluster: mail"},
|
||||
{0xF8, "cluster: miscellaneous applications"},
|
||||
};
|
||||
|
||||
static const char unknownAID[] = "";
|
||||
|
||||
static const char *GetAIDDescription(uint16_t AID) {
|
||||
for(int i = 0; i < ARRAYLEN(madKnownAIDs); i++)
|
||||
if (madKnownAIDs[i].AID == AID)
|
||||
return madKnownAIDs[i].Description;
|
||||
|
||||
for(int i = 0; i < ARRAYLEN(madKnownClusterCodes); i++)
|
||||
if (madKnownClusterCodes[i].AID == (AID >> 8)) // high byte - cluster code
|
||||
return madKnownClusterCodes[i].Description;
|
||||
|
||||
return unknownAID;
|
||||
}
|
||||
|
||||
int madCRCCheck(uint8_t *sector, bool verbose, int MADver) {
|
||||
if (MADver == 1) {
|
||||
uint8_t crc = CRC8Mad(§or[16 + 1], 15 + 16);
|
||||
if (crc != sector[16]) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]);
|
||||
return 3;
|
||||
};
|
||||
} else {
|
||||
uint8_t crc = CRC8Mad(§or[1], 15 + 16 + 16);
|
||||
if (crc != sector[0]) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(ERR, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]);
|
||||
return 3;
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) {
|
||||
if (MADver == 1)
|
||||
return (sector[16 + 2 + (sectorNo - 1) * 2] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2 + 1]);
|
||||
else
|
||||
return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]);
|
||||
}
|
||||
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) {
|
||||
|
||||
uint8_t GPB = sector[3 * 16 + 9];
|
||||
PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB);
|
||||
|
||||
// DA (MAD available)
|
||||
if (!(GPB & 0x80)) {
|
||||
PrintAndLogEx(ERR, "DA=0! MAD not available.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// MA (multi-application card)
|
||||
if (GPB & 0x40)
|
||||
PrintAndLogEx(NORMAL, "Multi application card.");
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Single application card.");
|
||||
|
||||
uint8_t MADVer = GPB & 0x03;
|
||||
PrintAndLogEx(NORMAL, "MAD version: %d", MADVer);
|
||||
|
||||
// MAD version
|
||||
if ((MADVer != 0x01) && (MADVer != 0x02)) {
|
||||
PrintAndLogEx(ERR, "Wrong MAD version: 0x%02x", MADVer);
|
||||
return 2;
|
||||
};
|
||||
|
||||
if (haveMAD2)
|
||||
*haveMAD2 = (MADVer == 2);
|
||||
|
||||
int res = madCRCCheck(sector, true, 1);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "CRC8-MAD OK.");
|
||||
|
||||
// info byte
|
||||
uint8_t InfoByte = sector[16 + 1] & 0x3f;
|
||||
if (InfoByte) {
|
||||
PrintAndLogEx(NORMAL, "Card publisher sector: 0x%02x", InfoByte);
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "Card publisher sector not present.");
|
||||
}
|
||||
if (InfoByte == 0x10 || InfoByte >= 0x28)
|
||||
PrintAndLogEx(WARNING, "Info byte error");
|
||||
|
||||
PrintAndLogEx(NORMAL, "00 MAD1");
|
||||
for(int i = 1; i < 16; i++) {
|
||||
uint16_t AID = madGetAID(sector, 1, i);
|
||||
PrintAndLogEx(NORMAL, "%02d [%04X] %s", i, AID, GetAIDDescription(AID));
|
||||
};
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool verbose) {
|
||||
PrintAndLogEx(NORMAL, "16 MAD2");
|
||||
|
||||
int res = madCRCCheck(sector, true, 2);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, "CRC8-MAD OK.");
|
||||
|
||||
uint8_t InfoByte = sector[1] & 0x3f;
|
||||
PrintAndLogEx(NORMAL, "MAD2 Card publisher sector: 0x%02x", InfoByte);
|
||||
|
||||
for(int i = 1; i < 8 + 8 + 7 + 1; i++) {
|
||||
uint16_t AID = madGetAID(sector, 2, i);
|
||||
PrintAndLogEx(NORMAL, "%02d [%04X] %s", i + 16, AID, GetAIDDescription(AID));
|
||||
};
|
||||
|
||||
return 0;
|
||||
};
|
26
client/mifare/mad.h
Normal file
26
client/mifare/mad.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2019 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 Application Directory (MAD) functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _MAD_H_
|
||||
#define _MAD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t AID;
|
||||
const char *Description;
|
||||
} madAIDDescr;
|
||||
|
||||
int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2);
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool verbose);
|
||||
|
||||
|
||||
#endif // _MAD_H_
|
|
@ -17,6 +17,39 @@
|
|||
#include "ui.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
static bool VerboseMode = false;
|
||||
void mfpSetVerboseMode(bool verbose) {
|
||||
VerboseMode = verbose;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t Code;
|
||||
const char *Description;
|
||||
} PlusErrorsElm;
|
||||
|
||||
static const PlusErrorsElm PlusErrors[] = {
|
||||
{0xFF, ""},
|
||||
{0x00, "Transfer cannot be granted within the current authentication."},
|
||||
{0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."},
|
||||
{0x07, "Too many read or write commands in the session or in the transaction."},
|
||||
{0x08, "Invalid MAC in command or response"},
|
||||
{0x09, "Block Number is not valid"},
|
||||
{0x0a, "Invalid block number, not existing block number"},
|
||||
{0x0b, "The current command code not available at the current card state."},
|
||||
{0x0c, "Length error"},
|
||||
{0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."},
|
||||
{0x90, "OK"},
|
||||
};
|
||||
int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
|
||||
|
||||
const char * mfpGetErrorDescription(uint8_t errorCode) {
|
||||
for(int i = 0; i < PlusErrorsLen; i++)
|
||||
if (errorCode == PlusErrors[i].Code)
|
||||
return PlusErrors[i].Description;
|
||||
|
||||
return PlusErrors[0].Description;
|
||||
}
|
||||
|
||||
AccessConditions_t MFAccessConditions[] = {
|
||||
{0x00, "rdAB wrAB incAB dectrAB"},
|
||||
{0x01, "rdAB dectrAB"},
|
||||
|
@ -274,6 +307,130 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF
|
|||
return 0;
|
||||
}
|
||||
|
||||
int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
||||
|
||||
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
|
||||
if(VerboseMode)
|
||||
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
|
||||
memmove(&rcmd[3], key, 16);
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
uint8_t rcmd[1] = {0xaa};
|
||||
|
||||
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
}
|
||||
|
||||
int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount};
|
||||
if (!plain && session)
|
||||
CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->R_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
|
||||
memmove(&rcmd[3], data, 16);
|
||||
if (session)
|
||||
CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
if (session)
|
||||
session->W_Ctr++;
|
||||
|
||||
if(session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose){
|
||||
uint8_t keyn[2] = {0};
|
||||
bool plain = false;
|
||||
|
||||
uint16_t uKeyNum = 0x4000 + sectorNo * 2 + (keyType ? 1 : 0);
|
||||
keyn[0] = uKeyNum >> 8;
|
||||
keyn[1] = uKeyNum & 0xff;
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum);
|
||||
|
||||
mf4Session session;
|
||||
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t data[250] = {0};
|
||||
int datalen = 0;
|
||||
uint8_t mac[8] = {0};
|
||||
uint8_t firstBlockNo = mfFirstBlockOfSector(sectorNo);
|
||||
for(int n = firstBlockNo; n < firstBlockNo + mfNumBlocksPerSector(sectorNo); n++) {
|
||||
res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Sector %d read error: %d", sectorNo, res);
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (datalen && data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Sector %d card read error: %02x %s", sectorNo, data[0], mfpGetErrorDescription(data[0]));
|
||||
DropField();
|
||||
return 5;
|
||||
}
|
||||
if (datalen != 1 + 16 + 8 + 2) {
|
||||
PrintAndLogEx(ERR, "Sector %d error returned data length:%d", sectorNo, datalen);
|
||||
DropField();
|
||||
return 6;
|
||||
}
|
||||
|
||||
memcpy(&dataout[(n - firstBlockNo) * 16], &data[1], 16);
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16));
|
||||
|
||||
if (memcmp(&data[1 + 16], mac, 8)) {
|
||||
PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n);
|
||||
PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8));
|
||||
PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8));
|
||||
|
||||
if (!verbose)
|
||||
return 7;
|
||||
} else {
|
||||
if(verbose)
|
||||
PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8));
|
||||
}
|
||||
}
|
||||
DropField();
|
||||
|
||||
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) {
|
|
@ -43,9 +43,18 @@ typedef struct {
|
|||
char *description;
|
||||
} AccessConditions_t;
|
||||
|
||||
extern void mfpSetVerboseMode(bool verbose);
|
||||
extern const char * mfpGetErrorDescription(uint8_t errorCode);
|
||||
|
||||
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 int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
extern int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
extern int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
extern int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||
extern int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose);
|
||||
|
||||
extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data);
|
||||
|
||||
extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
|
|
@ -31,7 +31,7 @@ static const uint64_t g_mifare_default_keys[] =
|
|||
0xabcdef123456,
|
||||
0x4d3a99c351dd,
|
||||
0x1a982c7e459a,
|
||||
0xd3f7d3f7d3f7,
|
||||
0xd3f7d3f7d3f7, // NDEF public key
|
||||
0x714c5c886e97,
|
||||
0x587ee5f9350f,
|
||||
0xa0478cc39091,
|
||||
|
@ -42,4 +42,8 @@ static const uint64_t g_mifare_default_keys[] =
|
|||
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};
|
||||
static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7};
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
// Merlok, 2011, 2012
|
||||
// Merlok, 2011, 2012, 2019
|
||||
// people from mifare@nethemba.com, 2010
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
|
@ -414,6 +414,32 @@ out:
|
|||
return -4;
|
||||
}
|
||||
|
||||
// MIFARE
|
||||
int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) {
|
||||
|
||||
UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}};
|
||||
memcpy(c.d.asBytes, key, 6);
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
UsbCommand resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.arg[0] & 0xff;
|
||||
|
||||
if (isOK) {
|
||||
memcpy(data, resp.d.asBytes, mfNumBlocksPerSector(sectorNo) * 16);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Command execute timeout");
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EMULATOR
|
||||
int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) {
|
||||
UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}};
|
|
@ -1,4 +1,4 @@
|
|||
// Merlok, 2011
|
||||
// Merlok, 2011, 2019
|
||||
// people from mifare@nethemba.com, 2010
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
|
@ -76,7 +76,7 @@ extern int mfCheckKeys_fast( uint8_t sectorsCnt, uint8_t firstChunk, uint8_t las
|
|||
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);
|
0
client/obj/mifare/.dummy
Normal file
0
client/obj/mifare/.dummy
Normal file
|
@ -19,7 +19,7 @@
|
|||
#include "cmdmain.h"
|
||||
#include "comms.h"
|
||||
#include "util.h"
|
||||
#include "mifarehost.h"
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "crc.h"
|
||||
#include "crc16.h"
|
||||
#include "crc64.h"
|
||||
|
|
|
@ -99,14 +99,13 @@ uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
|
|||
crc_update2(&crc, buff[i], 8);
|
||||
return crc_finish(&crc);
|
||||
}
|
||||
// width=8 poly=0x1d, reversed poly=0x?? init=0xe3 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/MAD"
|
||||
// the CRC needs to be reversed before returned.
|
||||
// width=8 poly=0x1d, init=0xc7 (0xe3 - WRONG! but it mentioned in MAD datasheet) refin=false refout=false xorout=0x00 name="CRC-8/MIFARE-MAD"
|
||||
uint32_t CRC8Mad(uint8_t *buff, size_t size) {
|
||||
crc_t crc;
|
||||
crc_init_ref(&crc, 8, 0x1d, 0xe3, 0, true, true);
|
||||
crc_init_ref(&crc, 8, 0x1d, 0xc7, 0, false, false);
|
||||
for ( int i = 0; i < size; ++i)
|
||||
crc_update2(&crc, buff[i], 8);
|
||||
return reflect8(crc_finish(&crc));
|
||||
return crc_finish(&crc);
|
||||
}
|
||||
// width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC"
|
||||
uint32_t CRC4Legic(uint8_t *cmd, size_t size) {
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define MF_KEY_A 0
|
||||
#define MF_KEY_B 1
|
||||
|
||||
#define MF_MAD1_SECTOR 0x00
|
||||
#define MF_MAD2_SECTOR 0x10
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO 14443A
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Reference in a new issue