Compare commits
8 Commits
mfoc-0.09
...
mfoc-0.10.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e076683dea | ||
|
|
4d1ce73772 | ||
|
|
dafa6e42db | ||
|
|
c973c3cd81 | ||
|
|
6a3977545e | ||
|
|
af8ec581be | ||
|
|
d4eb0e3eba | ||
|
|
0320ded902 |
10
configure.ac
10
configure.ac
@@ -1,4 +1,4 @@
|
||||
AC_INIT([mfoc], [0.09], [mifare@nethemba.com])
|
||||
AC_INIT([mfoc], [0.10.1], [mifare@nethemba.com])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
@@ -13,11 +13,11 @@ AM_INIT_AUTOMAKE
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for pkg-config modules.
|
||||
LIBNFC_REQUIRED_VERSION=1.3.9
|
||||
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
|
||||
LIBNFC_REQUIRED_VERSION=1.4.2
|
||||
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
|
||||
|
||||
PKG_CONFIG_REQUIRES="libnfc"
|
||||
AC_SUBST([PKG_CONFIG_REQUIRES])
|
||||
PKG_CONFIG_REQUIRES="libnfc"
|
||||
AC_SUBST([PKG_CONFIG_REQUIRES])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
AM_CFLAGS = @LIBNFC_CFLAGS@
|
||||
AM_LDFLAGS = @LIBNFC_LIBS@
|
||||
|
||||
bin_PROGRAMS = mfoc
|
||||
|
||||
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h
|
||||
mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c
|
||||
mfoc_LDADD = @LIBNFC_LIBS@
|
||||
|
||||
# dist_man_MANS = mfoc.1
|
||||
|
||||
143
src/mfoc.c
143
src/mfoc.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Mifare Classic Offline Cracker version 0.08
|
||||
Mifare Classic Offline Cracker
|
||||
|
||||
Requirements: crapto1 library http://code.google.com/p/crapto1
|
||||
libnfc http://www.libnfc.org
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
Porting to libnfc 1.3.3: Michal Boska <boska.michal@gmail.com>
|
||||
Porting to libnfc 1.3.9: Romuald Conty <romuald@libnfc.org>
|
||||
Porting to libnfc 1.4.x: Romuald Conty <romuald@libnfc.org>
|
||||
|
||||
URL http://eprint.iacr.org/2009/137.pdf
|
||||
URL http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf
|
||||
@@ -106,27 +107,27 @@ int main(int argc, char * const argv[]) {
|
||||
case 'P':
|
||||
// Number of probes
|
||||
if (!(probes = atoi(optarg)) || probes < 1) {
|
||||
fprintf(stderr, "The number of probes must be a positive number\n");
|
||||
exit(1);
|
||||
ERR ("The number of probes must be a positive number");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// fprintf(stdout, "Number of probes: %d\n", probes);
|
||||
break;
|
||||
case 'T':
|
||||
// Nonce tolerance range
|
||||
if (!(d.tolerance = atoi(optarg)) || d.tolerance < 0) {
|
||||
fprintf(stderr, "The nonce distances range must be a zero or a positive number\n");
|
||||
exit(1);
|
||||
ERR ("The nonce distances range must be a zero or a positive number");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// fprintf(stdout, "Tolerance number: %d\n", probes);
|
||||
break;
|
||||
case 'k':
|
||||
// Add this key to the default keys list
|
||||
if ((defKey = calloc(6, sizeof(byte_t))) == NULL) {
|
||||
fprintf(stderr, "Cannot allocate memory for defKey\n");
|
||||
exit(1);
|
||||
ERR ("Cannot allocate memory for defKey");
|
||||
exit (EXIT_FAILURE);
|
||||
} else {
|
||||
bzero(defKey, 6);
|
||||
num_to_bytes(strtol(optarg, NULL, 16), 6, defKey);
|
||||
num_to_bytes(strtoll(optarg, NULL, 16), 6, defKey);
|
||||
memcpy(defaultKeys[0], defKey, 6);
|
||||
}
|
||||
fprintf(stdout, "The custom key 0x%012llx has been added to the default keys\n", bytes_to_num(defKey, 6));
|
||||
@@ -136,7 +137,7 @@ int main(int argc, char * const argv[]) {
|
||||
// File output
|
||||
if (!(pfDump = fopen(optarg, "wb"))) {
|
||||
fprintf(stderr, "Cannot open: %s, exiting\n", optarg);
|
||||
exit(1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// fprintf(stdout, "Output file: %s\n", optarg);
|
||||
break;
|
||||
@@ -150,35 +151,35 @@ int main(int argc, char * const argv[]) {
|
||||
}
|
||||
|
||||
if (!pfDump) {
|
||||
fprintf(stderr, "Error, parameter -O is mandatory\n");
|
||||
exit(1);
|
||||
ERR ("parameter -O is mandatory");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize reader/tag structures
|
||||
mf_init(&t, &r);
|
||||
// Configure reader settings
|
||||
mf_configure(r.pdi);
|
||||
mf_select_tag(r.pdi, &t.ti);
|
||||
mf_select_tag(r.pdi, &(t.nt));
|
||||
|
||||
// Save tag uid and info about block size (b4K)
|
||||
t.b4K = (t.ti.nai.abtAtqa[1] == 0x02);
|
||||
t.uid = (uint32_t) bytes_to_num(t.ti.nai.abtUid, 4);
|
||||
t.b4K = (t.nt.nti.nai.abtAtqa[1] == 0x02);
|
||||
t.uid = (uint32_t) bytes_to_num(t.nt.nti.nai.abtUid, 4);
|
||||
|
||||
t.num_blocks = (t.b4K) ? 0xff : 0x3f;
|
||||
t.num_sectors = t.b4K ? NR_TRAILERS_4k : NR_TRAILERS_1k;
|
||||
|
||||
t.sectors = (void *) calloc(t.num_sectors, sizeof(sector));
|
||||
if (t.sectors == NULL) {
|
||||
fprintf(stderr, "Cannot allocate memory for t.sectors\n");
|
||||
exit(1);
|
||||
ERR ("Cannot allocate memory for t.sectors");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if ((pk = (void *) malloc(sizeof(pKeys))) == NULL) {
|
||||
fprintf(stderr, "Cannot allocate memory for pk\n");
|
||||
exit(1);
|
||||
ERR ("Cannot allocate memory for pk");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if ((bk = (void *) malloc(sizeof(bKeys))) == NULL) {
|
||||
fprintf(stderr, "Cannot allocate memory for bk\n");
|
||||
exit(1);
|
||||
ERR ("Cannot allocate memory for bk");
|
||||
exit (EXIT_FAILURE);
|
||||
} else {
|
||||
bk->brokenKeys = NULL;
|
||||
bk->size = 0;
|
||||
@@ -186,15 +187,15 @@ int main(int argc, char * const argv[]) {
|
||||
|
||||
d.distances = (void *) calloc(d.num_distances, sizeof(u_int32_t));
|
||||
if (d.distances == NULL) {
|
||||
fprintf(stderr, "Cannot allocate memory for t.distances\n");
|
||||
exit(1);
|
||||
ERR ("Cannot allocate memory for t.distances");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Test if a compatible MIFARE tag is used
|
||||
if ((t.ti.nai.btSak & 0x08) == 0) {
|
||||
printf("Error: inserted tag is not a MIFARE Classic card\n");
|
||||
if ((t.nt.nti.nai.btSak & 0x08) == 0) {
|
||||
ERR ("inserted tag is not a MIFARE Classic");
|
||||
nfc_disconnect(r.pdi);
|
||||
exit(1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Initialize t.sectors, keys are not known yet
|
||||
@@ -206,7 +207,7 @@ int main(int argc, char * const argv[]) {
|
||||
|
||||
// Try to authenticate to all sectors with default keys
|
||||
// Set the authentication information (uid)
|
||||
memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid));
|
||||
memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid));
|
||||
// Iterate over all keys (n = number of keys)
|
||||
n = sizeof(defaultKeys)/sizeof(defaultKeys[0]);
|
||||
for (key = 0; key < n; key++) {
|
||||
@@ -276,7 +277,7 @@ int main(int argc, char * const argv[]) {
|
||||
for (m = 0; m < 2; ++m) {
|
||||
if (e_sector == -1) break; // All keys are default, I am skipping recovery mode
|
||||
for (j = 0; j < (t.num_sectors); ++j) {
|
||||
memcpy(mp.mpa.abtUid, t.ti.nai.abtUid, sizeof(mp.mpa.abtUid));
|
||||
memcpy(mp.mpa.abtUid, t.nt.nti.nai.abtUid, sizeof(mp.mpa.abtUid));
|
||||
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
||||
|
||||
// First, try already broken keys
|
||||
@@ -371,8 +372,8 @@ int main(int argc, char * const argv[]) {
|
||||
}
|
||||
// We haven't found any key, exiting
|
||||
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
||||
fprintf(stderr, "No success, maybe you should increase the probes\n");
|
||||
exit(1);
|
||||
ERR ("No success, maybe you should increase the probes");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +400,7 @@ int main(int argc, char * const argv[]) {
|
||||
// Try A key, auth() + read()
|
||||
memcpy(mp.mpa.abtKey, t.sectors[i].KeyA, sizeof(t.sectors[i].KeyA));
|
||||
if (!nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_A, block, &mp)) {
|
||||
// fprintf(stderr, "Error: Auth A\n");
|
||||
// ERR ("Error: Auth A");
|
||||
mf_configure(r.pdi);
|
||||
mf_anticollision(t, r);
|
||||
} else { // and Read
|
||||
@@ -407,16 +408,16 @@ int main(int argc, char * const argv[]) {
|
||||
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6));
|
||||
print_hex(mp.mpd.abtData, 16);
|
||||
mf_configure(r.pdi);
|
||||
mf_select_tag(r.pdi, &t.ti);
|
||||
mf_select_tag(r.pdi, &(t.nt));
|
||||
failure = false;
|
||||
} else {
|
||||
// Error, now try read() with B key
|
||||
// fprintf(stderr, "Error: Read A\n");
|
||||
// ERR ("Error: Read A");
|
||||
mf_configure(r.pdi);
|
||||
mf_anticollision(t, r);
|
||||
memcpy(mp.mpa.abtKey, t.sectors[i].KeyB, sizeof(t.sectors[i].KeyB));
|
||||
if (!nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mp)) {
|
||||
// fprintf(stderr, "Error: Auth B\n");
|
||||
// ERR ("Error: Auth B");
|
||||
mf_configure(r.pdi);
|
||||
mf_anticollision(t, r);
|
||||
} else { // and Read
|
||||
@@ -424,12 +425,12 @@ int main(int argc, char * const argv[]) {
|
||||
fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6));
|
||||
print_hex(mp.mpd.abtData, 16);
|
||||
mf_configure(r.pdi);
|
||||
mf_select_tag(r.pdi, &t.ti);
|
||||
mf_select_tag(r.pdi, &(t.nt));
|
||||
failure = false;
|
||||
} else {
|
||||
mf_configure(r.pdi);
|
||||
mf_anticollision(t, r);
|
||||
// fprintf(stderr, "Error: Read B\n");
|
||||
// ERR ("Error: Read B");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,14 +441,14 @@ int main(int argc, char * const argv[]) {
|
||||
memcpy(mtDump.amb[block].mbt.abtKeyB,t.sectors[i].KeyB,6);
|
||||
if (!failure) memcpy(mtDump.amb[block].mbt.abtAccessBits,mp.mpd.abtData+6,4);
|
||||
} else if (!failure) memcpy(mtDump.amb[block].mbd.abtData, mp.mpd.abtData,16);
|
||||
memcpy(mp.mpa.abtUid,t.ti.nai.abtUid,4);
|
||||
memcpy(mp.mpa.abtUid,t.nt.nti.nai.abtUid,4);
|
||||
}
|
||||
|
||||
// Finally save all keys + data to file
|
||||
if (fwrite(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) {
|
||||
fprintf(stdout, "Error, cannot write dump\n");
|
||||
fclose(pfDump);
|
||||
exit(1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
fclose(pfDump);
|
||||
}
|
||||
@@ -488,8 +489,8 @@ void mf_init(mftag *t, mfreader *r) {
|
||||
// Connect to the first NFC device
|
||||
r->pdi = nfc_connect(NULL);
|
||||
if (!r->pdi) {
|
||||
fprintf(stderr, "!Error connecting to the NFC reader\n");
|
||||
exit(1);
|
||||
ERR ("Unable to connect to NFC device\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,12 +507,16 @@ void mf_configure(nfc_device_t* pdi) {
|
||||
nfc_configure(pdi,NDO_ACTIVATE_FIELD,true);
|
||||
}
|
||||
|
||||
void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti) {
|
||||
void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt) {
|
||||
// Poll for a ISO14443A (MIFARE) tag
|
||||
if (!nfc_initiator_select_passive_target(pdi,NM_ISO14443A_106,NULL,0,ti)) {
|
||||
fprintf(stderr, "!Error connecting to the MIFARE Classic tag\n");
|
||||
const nfc_modulation_t nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
};
|
||||
if (!nfc_initiator_select_passive_target(pdi, nm, NULL, 0, pnt)) {
|
||||
ERR ("Unable to connect to the MIFARE Classic tag");
|
||||
nfc_disconnect(pdi);
|
||||
exit(1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,14 +547,18 @@ int find_exploit_sector(mftag t) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n\nNo sector encrypted with the default key has been found, exiting..\n");
|
||||
exit(1);
|
||||
ERR ("\n\nNo sector encrypted with the default key has been found, exiting..");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void mf_anticollision(mftag t, mfreader r) {
|
||||
if (!nfc_initiator_select_passive_target(r.pdi, NM_ISO14443A_106, NULL, 0, &t.ti)) {
|
||||
fprintf(stderr, "\n\n!Error: tag has been removed\n");
|
||||
exit(1);
|
||||
const nfc_modulation_t nm = {
|
||||
.nmt = NMT_ISO14443A,
|
||||
.nbr = NBR_106,
|
||||
};
|
||||
if (!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) {
|
||||
ERR ("\n\n!Error: tag has been removed");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,7 +590,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
|
||||
// Prepare AUTH command
|
||||
Auth[0] = (t.sectors[e_sector].foundKeyA) ? 0x60 : 0x61;
|
||||
append_iso14443a_crc(Auth,2);
|
||||
iso14443a_crc_append (Auth,2);
|
||||
// fprintf(stdout, "\nAuth command:\t");
|
||||
// print_hex(Auth, 4);
|
||||
|
||||
@@ -646,8 +655,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
// fprintf(stdout, "\t{Ar}:\t");
|
||||
// print_hex_par(ArEnc, 64, ArEncPar);
|
||||
if ((!nfc_initiator_transceive_bits(r.pdi, ArEnc, 64, ArEncPar, Rx, &RxLen, RxPar)) || (RxLen != 32)) {
|
||||
fprintf(stderr, "Reader-answer transfer error, exiting..\n");
|
||||
exit(1);
|
||||
ERR ("Reader-answer transfer error, exiting..");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Now print the answer from the tag
|
||||
@@ -657,8 +666,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
// Decrypt the tag answer and verify that suc3(Nt) is At
|
||||
Nt = prng_successor(Nt, 32);
|
||||
if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt&0xFFFFFFFF))) {
|
||||
fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting..\n");
|
||||
exit(1);
|
||||
ERR ("[At] is not Suc3(Nt), something is wrong, exiting..");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
// fprintf(stdout, "Authentication completed.\n\n");
|
||||
|
||||
@@ -676,7 +685,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
// Sending the encrypted Auth command
|
||||
if (!nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar,Rx, &RxLen, RxPar)) {
|
||||
fprintf(stdout, "Error requesting encrypted tag-nonce\n");
|
||||
exit(1);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Decrypt the encrypted auth
|
||||
@@ -704,13 +713,13 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
}
|
||||
nfc_configure(r.pdi,NDO_HANDLE_PARITY,false);
|
||||
if ((!nfc_initiator_transceive_bits(r.pdi, ArEnc, 64, ArEncPar, Rx, &RxLen, RxPar)) || (RxLen != 32)) {
|
||||
fprintf(stderr, "Reader-answer transfer error, exiting..\n");
|
||||
exit(1);
|
||||
ERR ("Reader-answer transfer error, exiting..");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
Nt = prng_successor(Nt, 32);
|
||||
if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt&0xFFFFFFFF))) {
|
||||
fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting..\n");
|
||||
exit(1);
|
||||
ERR ("[At] is not Suc3(Nt), something is wrong, exiting..");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
} // Next auth probe
|
||||
|
||||
@@ -724,7 +733,7 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
|
||||
Auth[0] = dumpKeysA ? 0x60 : 0x61;
|
||||
Auth[1] = a_sector;
|
||||
append_iso14443a_crc(Auth,2);
|
||||
iso14443a_crc_append (Auth,2);
|
||||
|
||||
// Encryption of the Auth command, sending the Auth command
|
||||
for (i = 0; i < 4; i++) {
|
||||
@@ -733,8 +742,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
|
||||
}
|
||||
if (!nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar,Rx, &RxLen, RxPar)) {
|
||||
fprintf(stdout, "Error requesting encrypted tag-nonce\n");
|
||||
exit(1);
|
||||
ERR ("while requesting encrypted tag-nonce");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Save the encrypted nonce
|
||||
@@ -770,8 +779,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
// fprintf(stdout, "New chunk by %d, sizeof %lu\n", kcount, pk->size * sizeof(uint64_t));
|
||||
pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t));
|
||||
if (pk->possibleKeys == NULL) {
|
||||
fprintf(stderr, "Memory allocation error for pk->possibleKeys\n");
|
||||
exit(1);
|
||||
ERR ("Memory allocation error for pk->possibleKeys");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
pk->possibleKeys[kcount] = lfsr;
|
||||
@@ -786,8 +795,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
||||
if (kcount != 0) {
|
||||
pk->size = --kcount;
|
||||
if ((pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t))) == NULL) {
|
||||
fprintf(stderr, "Memory allocation error for pk->possibleKeys\n");
|
||||
exit(1);
|
||||
ERR ("Memory allocation error for pk->possibleKeys");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,8 +836,8 @@ countKeys * uniqsort(uint64_t * possibleKeys, uint32_t size) {
|
||||
|
||||
our_counts = calloc(size, sizeof(countKeys));
|
||||
if (our_counts == NULL) {
|
||||
fprintf(stderr, "Memory allocation error for our_counts\n");
|
||||
exit(1);
|
||||
ERR ("Memory allocation error for our_counts");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
|
||||
@@ -40,7 +40,7 @@ typedef struct {
|
||||
} denonce; // Revealed information about nonce
|
||||
|
||||
typedef struct {
|
||||
nfc_target_info_t ti;
|
||||
nfc_target_t nt;
|
||||
sector * sectors; // Allocate later, we do not know the number of sectors yet
|
||||
sector e_sector; // Exploit sector
|
||||
uint32_t num_sectors;
|
||||
@@ -72,7 +72,7 @@ typedef struct {
|
||||
void usage(FILE * stream, int errno);
|
||||
void mf_init(mftag *t, mfreader *r);
|
||||
void mf_configure(nfc_device_t* pdi);
|
||||
void mf_select_tag(nfc_device_t* pdi, nfc_target_info_t* ti);
|
||||
void mf_select_tag(nfc_device_t* pdi, nfc_target_t* pnt);
|
||||
int trailer_block(uint32_t block);
|
||||
int find_exploit_sector(mftag t);
|
||||
void mf_anticollision(mftag t, mfreader r);
|
||||
|
||||
66
src/mifare.c
66
src/mifare.c
@@ -1,3 +1,33 @@
|
||||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mifare.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -21,13 +51,10 @@ bool
|
||||
nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param * pmp)
|
||||
{
|
||||
byte_t abtRx[265];
|
||||
size_t szRxLen;
|
||||
size_t szRx = sizeof(abtRx);
|
||||
size_t szParamLen;
|
||||
byte_t abtCmd[265];
|
||||
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pnd->bActive)
|
||||
return false;
|
||||
bool bEasyFraming;
|
||||
|
||||
abtCmd[0] = mc; // The MIFARE Classic command
|
||||
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||
@@ -67,15 +94,34 @@ nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t
|
||||
if (szParamLen)
|
||||
memcpy (abtCmd + 2, (byte_t *) pmp, szParamLen);
|
||||
|
||||
// Fire the mifare command
|
||||
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRxLen)) {
|
||||
if (pnd->iLastError != 0x14)
|
||||
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
|
||||
bEasyFraming = pnd->bEasyFraming;
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, true)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
return false;
|
||||
}
|
||||
// Fire the mifare command
|
||||
if (!nfc_initiator_transceive_bytes (pnd, abtCmd, 2 + szParamLen, abtRx, &szRx)) {
|
||||
if (pnd->iLastError == EINVRXFRAM) {
|
||||
// "Invalid received frame" AKA EINVRXFRAM, usual means we are
|
||||
// authenticated on a sector but the requested MIFARE cmd (read, write)
|
||||
// is not permitted by current acces bytes;
|
||||
// So there is nothing to do here.
|
||||
} else if (pnd->iLastError == EMFAUTH) {
|
||||
// In MFOC, we have to hide authentication errors :)
|
||||
} else {
|
||||
nfc_perror (pnd, "nfc_initiator_transceive_bytes");
|
||||
}
|
||||
nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming);
|
||||
return false;
|
||||
}
|
||||
if (!nfc_configure (pnd, NDO_EASY_FRAMING, bEasyFraming)) {
|
||||
nfc_perror (pnd, "nfc_configure");
|
||||
return false;
|
||||
}
|
||||
|
||||
// When we have executed a read command, copy the received bytes into the param
|
||||
if (mc == MC_READ) {
|
||||
if (szRxLen == 16) {
|
||||
if (szRx == 16) {
|
||||
memcpy (pmp->mpd.abtData, abtRx, 16);
|
||||
} else {
|
||||
return false;
|
||||
|
||||
42
src/mifare.h
42
src/mifare.h
@@ -1,22 +1,34 @@
|
||||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult, 2010, Romuald Conty
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mifaretag.h
|
||||
* @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc
|
||||
*/
|
||||
|
||||
578
src/nfc-utils.c
578
src/nfc-utils.c
@@ -1,4 +1,35 @@
|
||||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
#include <nfc/nfc.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "nfc-utils.h"
|
||||
|
||||
@@ -97,35 +128,411 @@ print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDa
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
#define SAK_UID_NOT_COMPLETE 0x04
|
||||
#define SAK_ISO14443_4_COMPLIANT 0x20
|
||||
#define SAK_ISO18092_COMPLIANT 0x40
|
||||
|
||||
void
|
||||
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai)
|
||||
print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose)
|
||||
{
|
||||
printf (" ATQA (SENS_RES): ");
|
||||
print_hex (nai.abtAtqa, 2);
|
||||
if (verbose) {
|
||||
printf("* UID size: ");
|
||||
switch ((nai.abtAtqa[1] & 0xc0)>>6) {
|
||||
case 0:
|
||||
printf("single\n");
|
||||
break;
|
||||
case 1:
|
||||
printf("double\n");
|
||||
break;
|
||||
case 2:
|
||||
printf("triple\n");
|
||||
break;
|
||||
case 3:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf("* bit frame anticollision ");
|
||||
switch (nai.abtAtqa[1] & 0x1f) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x04:
|
||||
case 0x08:
|
||||
case 0x10:
|
||||
printf("supported\n");
|
||||
break;
|
||||
default:
|
||||
printf("not supported\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf (" UID (NFCID%c): ", (nai.abtUid[0] == 0x08 ? '3' : '1'));
|
||||
print_hex (nai.abtUid, nai.szUidLen);
|
||||
if (verbose) {
|
||||
if (nai.abtUid[0] == 0x08) {
|
||||
printf ("* Random UID\n");
|
||||
}
|
||||
}
|
||||
printf (" SAK (SEL_RES): ");
|
||||
print_hex (&nai.btSak, 1);
|
||||
if (verbose) {
|
||||
if (nai.btSak & SAK_UID_NOT_COMPLETE) {
|
||||
printf ("* Warning! Cascade bit set: UID not complete\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT) {
|
||||
printf ("* Compliant with ISO/IEC 14443-4\n");
|
||||
} else {
|
||||
printf ("* Not compliant with ISO/IEC 14443-4\n");
|
||||
}
|
||||
if (nai.btSak & SAK_ISO18092_COMPLIANT) {
|
||||
printf ("* Compliant with ISO/IEC 18092\n");
|
||||
} else {
|
||||
printf ("* Not compliant with ISO/IEC 18092\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen) {
|
||||
printf (" ATS (ATR): ");
|
||||
printf (" ATS: ");
|
||||
print_hex (nai.abtAts, nai.szAtsLen);
|
||||
}
|
||||
if ((nai.btSak & SAK_ISO14443_4_COMPLIANT) || (nai.btSak & SAK_ISO18092_COMPLIANT)) {
|
||||
printf (" Compliant with: ");
|
||||
if (nai.btSak & SAK_ISO14443_4_COMPLIANT)
|
||||
printf ("ISO/IEC 14443-4 ");
|
||||
if (nai.btSak & SAK_ISO18092_COMPLIANT)
|
||||
printf ("ISO/IEC 18092");
|
||||
printf ("\n");
|
||||
if (nai.szAtsLen && verbose) {
|
||||
// Decode ATS according to ISO/IEC 14443-4 (5.2 Answer to select)
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf ("* Max Frame Size accepted by PICC: %d bytes\n", iMaxFrameSizes[nai.abtAts[0] & 0x0F]);
|
||||
|
||||
size_t offset = 1;
|
||||
if (nai.abtAts[0] & 0x10) { // TA(1) present
|
||||
byte_t TA = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf ("* Bit Rate Capability:\n");
|
||||
if (TA == 0) {
|
||||
printf (" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (TA & 1<<7) {
|
||||
printf (" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (TA & 1<<4) {
|
||||
printf (" * PICC to PCD, DS=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<5) {
|
||||
printf (" * PICC to PCD, DS=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<6) {
|
||||
printf (" * PICC to PCD, DS=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<0) {
|
||||
printf (" * PCD to PICC, DR=2, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<1) {
|
||||
printf (" * PCD to PICC, DR=4, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<2) {
|
||||
printf (" * PCD to PICC, DR=8, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (TA & 1<<3) {
|
||||
printf (" * ERROR unknown value\n");
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x20) { // TB(1) present
|
||||
byte_t TB= nai.abtAts[offset];
|
||||
offset++;
|
||||
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((TB & 0xf0) >> 4))/13560.0);
|
||||
if ((TB & 0x0f) == 0) {
|
||||
printf ("* No Start-up Frame Guard Time required\n");
|
||||
} else {
|
||||
printf ("* Start-up Frame Guard Time: %.4g ms\n",256.0*16.0*(1<<(TB & 0x0f))/13560.0);
|
||||
}
|
||||
}
|
||||
if (nai.abtAts[0] & 0x40) { // TC(1) present
|
||||
byte_t TC = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (TC & 0x1) {
|
||||
printf("* Node ADdress supported\n");
|
||||
} else {
|
||||
printf("* Node ADdress not supported\n");
|
||||
}
|
||||
if (TC & 0x2) {
|
||||
printf("* Card IDentifier supported\n");
|
||||
} else {
|
||||
printf("* Card IDentifier not supported\n");
|
||||
}
|
||||
}
|
||||
if (nai.szAtsLen > offset) {
|
||||
printf ("* Historical bytes Tk: " );
|
||||
print_hex (nai.abtAts + offset, (nai.szAtsLen - offset));
|
||||
byte_t CIB = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (CIB != 0x00 && CIB != 0x10 && (CIB & 0xf0) != 0x80) {
|
||||
printf(" * Proprietary format\n");
|
||||
if (CIB == 0xc1) {
|
||||
printf(" * Tag byte: Mifare or virtual cards of various types\n");
|
||||
byte_t L = nai.abtAts[offset];
|
||||
offset++;
|
||||
if (L != (nai.szAtsLen - offset)) {
|
||||
printf(" * Warning: Type Identification Coding length (%i)", L);
|
||||
printf(" not matching Tk length (%zi)\n", (nai.szAtsLen - offset));
|
||||
}
|
||||
if ((nai.szAtsLen - offset - 2) > 0) { // Omit 2 CRC bytes
|
||||
byte_t CTC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Type: ");
|
||||
switch (CTC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("(Multiple) Virtual Cards\n");
|
||||
break;
|
||||
case 0x10:
|
||||
printf("Mifare DESFire\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Mifare Plus\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Memory size: ");
|
||||
switch (CTC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("<1 kbyte\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("1 kbyte\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("2 kbyte\n");
|
||||
break;
|
||||
case 0x03:
|
||||
printf("4 kbyte\n");
|
||||
break;
|
||||
case 0x04:
|
||||
printf("8 kbyte\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
byte_t CVC = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Chip Status: ");
|
||||
switch (CVC & 0xf0) {
|
||||
case 0x00:
|
||||
printf("Engineering sample\n");
|
||||
break;
|
||||
case 0x20:
|
||||
printf("Released\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
printf(" * Chip Generation: ");
|
||||
switch (CVC & 0x0f) {
|
||||
case 0x00:
|
||||
printf("Generation 1\n");
|
||||
break;
|
||||
case 0x01:
|
||||
printf("Generation 2\n");
|
||||
break;
|
||||
case 0x02:
|
||||
printf("Generation 3\n");
|
||||
break;
|
||||
case 0x0f:
|
||||
printf("Unspecified\n");
|
||||
break;
|
||||
default:
|
||||
printf("RFU\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((nai.szAtsLen - offset) > 0) { // Omit 2 CRC bytes
|
||||
byte_t VCS = nai.abtAts[offset];
|
||||
offset++;
|
||||
printf(" * Specifics (Virtual Card Selection):\n");
|
||||
if ((VCS & 0x09) == 0x00) {
|
||||
printf(" * Only VCSL supported\n");
|
||||
} else if ((VCS & 0x09) == 0x01) {
|
||||
printf(" * VCS, VCSL and SVC supported\n");
|
||||
}
|
||||
if ((VCS & 0x0e) == 0x00) {
|
||||
printf(" * SL1, SL2(?), SL3 supported\n");
|
||||
} else if ((VCS & 0x0e) == 0x02) {
|
||||
printf(" * SL3 only card\n");
|
||||
} else if ((VCS & 0x0f) == 0x0e) {
|
||||
printf(" * No VCS command supported\n");
|
||||
} else if ((VCS & 0x0f) == 0x0f) {
|
||||
printf(" * Unspecified\n");
|
||||
} else {
|
||||
printf(" * RFU\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (CIB == 0x00) {
|
||||
printf(" * Tk after 0x00 consist of optional consecutive COMPACT-TLV data objects\n");
|
||||
printf(" followed by a mandatory status indicator (the last three bytes, not in TLV)\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
if (CIB == 0x10) {
|
||||
printf(" * DIR data reference: %02x\n", nai.abtAts[offset]);
|
||||
}
|
||||
if (CIB == 0x80) {
|
||||
if (nai.szAtsLen == offset) {
|
||||
printf(" * No COMPACT-TLV objects found, no status found\n");
|
||||
} else {
|
||||
printf(" * Tk after 0x80 consist of optional consecutive COMPACT-TLV data objects;\n");
|
||||
printf(" the last data object may carry a status indicator of one, two or three bytes.\n");
|
||||
printf(" See ISO/IEC 7816-4 8.1.1.3 for more info\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
printf("Fingerprinting based on ATQA & SAK values:\n");
|
||||
uint32_t atqasak = 0;
|
||||
atqasak += (((uint32_t)nai.abtAtqa[0] & 0xff)<<16);
|
||||
atqasak += (((uint32_t)nai.abtAtqa[1] & 0xff)<<8);
|
||||
atqasak += ((uint32_t)nai.btSak & 0xff);
|
||||
bool found_possible_match = false;
|
||||
switch (atqasak) {
|
||||
case 0x000218:
|
||||
printf("* Mifare Classic 4K\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000408:
|
||||
printf("* Mifare Classic 1K\n");
|
||||
printf("* Mifare Plus (4-byte UID) 2K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000409:
|
||||
printf("* Mifare MINI\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000410:
|
||||
printf("* Mifare Plus (4-byte UID) 2K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000411:
|
||||
printf("* Mifare Plus (4-byte UID) 4K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000418:
|
||||
printf("* Mifare Plus (4-byte UID) 4K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000420:
|
||||
printf("* Mifare Plus (4-byte UID) 2K/4K SL3\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004400:
|
||||
printf("* Mifare Ultralight\n");
|
||||
printf("* Mifare UltralightC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004208:
|
||||
case 0x004408:
|
||||
printf("* Mifare Plus (7-byte UID) 2K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004218:
|
||||
case 0x004418:
|
||||
printf("* Mifare Plus (7-byte UID) 4K SL1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004210:
|
||||
case 0x004410:
|
||||
printf("* Mifare Plus (7-byte UID) 2K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004211:
|
||||
case 0x004411:
|
||||
printf("* Mifare Plus (7-byte UID) 4K SL2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004220:
|
||||
case 0x004420:
|
||||
printf("* Mifare Plus (7-byte UID) 2K/4K SL3\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x034420:
|
||||
printf("* Mifare DESFire / Desfire EV1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Other matches not described in
|
||||
// AN MIFARE Type Identification Procedure
|
||||
// but seen in the field:
|
||||
switch (atqasak) {
|
||||
case 0x000488:
|
||||
printf("* Mifare Classic 1K Infineon\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000298:
|
||||
printf("* Gemplus MPCOS\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x030428:
|
||||
printf("* JCOP31\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x004820:
|
||||
printf("* JCOP31 v2.4.1\n");
|
||||
printf("* JCOP31 v2.2\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000428:
|
||||
printf("* JCOP31 v2.3.1\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000453:
|
||||
printf("* Fudan FM1208SH01\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000820:
|
||||
printf("* Fudan FM1208\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000238:
|
||||
printf("* MFC 4K emulated by Nokia 6212 Classic\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x000838:
|
||||
printf("* MFC 4K emulated by Nokia 6131 NFC\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
if ((nai.abtAtqa[0] & 0xf0) == 0) {
|
||||
switch (nai.abtAtqa[1]) {
|
||||
case 0x02:
|
||||
printf("* SmartMX with Mifare 4K emulation\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x04:
|
||||
printf("* SmartMX with Mifare 1K emulation\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
case 0x48:
|
||||
printf("* SmartMX with 7-byte UID\n");
|
||||
found_possible_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found_possible_match) {
|
||||
printf("* Unknown card, sorry\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_felica_info (const nfc_felica_info_t nfi)
|
||||
print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" ID (NFCID2): ");
|
||||
print_hex (nfi.abtId, 8);
|
||||
printf (" Parameter (PAD): ");
|
||||
@@ -133,18 +540,87 @@ print_nfc_felica_info (const nfc_felica_info_t nfi)
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi)
|
||||
print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose)
|
||||
{
|
||||
printf (" ATQB: ");
|
||||
print_hex (nbi.abtAtqb, 12);
|
||||
printf (" ID: ");
|
||||
print_hex (nbi.abtId, 4);
|
||||
printf (" CID: %02x\n", nbi.btCid);
|
||||
if (nbi.szInfLen > 0) {
|
||||
printf (" INF: ");
|
||||
print_hex (nbi.abtInf, nbi.szInfLen);
|
||||
(void) verbose;
|
||||
printf (" ATQA (SENS_RES): ");
|
||||
print_hex (nji.btSensRes, 2);
|
||||
printf (" 4-LSB JEWELID: ");
|
||||
print_hex (nji.btId, 4);
|
||||
}
|
||||
|
||||
#define PI_ISO14443_4_SUPPORTED 0x01
|
||||
#define PI_NAD_SUPPORTED 0x01
|
||||
#define PI_CID_SUPPORTED 0x02
|
||||
void
|
||||
print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose)
|
||||
{
|
||||
const int iMaxFrameSizes[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 };
|
||||
printf (" PUPI: ");
|
||||
print_hex (nbi.abtPupi, 4);
|
||||
printf (" Application Data: ");
|
||||
print_hex (nbi.abtApplicationData, 4);
|
||||
printf (" Protocol Info: ");
|
||||
print_hex (nbi.abtProtocolInfo, 3);
|
||||
if (verbose) {
|
||||
printf ("* Bit Rate Capability:\n");
|
||||
if (nbi.abtProtocolInfo[0] == 0) {
|
||||
printf (" * PICC supports only 106 kbits/s in both directions\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<7) {
|
||||
printf (" * Same bitrate in both directions mandatory\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<4) {
|
||||
printf (" * PICC to PCD, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<5) {
|
||||
printf (" * PICC to PCD, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<6) {
|
||||
printf (" * PICC to PCD, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<0) {
|
||||
printf (" * PCD to PICC, 1etu=64/fc, bitrate 212 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<1) {
|
||||
printf (" * PCD to PICC, 1etu=32/fc, bitrate 424 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<2) {
|
||||
printf (" * PCD to PICC, 1etu=16/fc, bitrate 847 kbits/s supported\n");
|
||||
}
|
||||
if (nbi.abtProtocolInfo[0] & 1<<3) {
|
||||
printf (" * ERROR unknown value\n");
|
||||
}
|
||||
if( (nbi.abtProtocolInfo[1] & 0xf0) <= 0x80 ) {
|
||||
printf ("* Maximum frame sizes: %d bytes\n", iMaxFrameSizes[((nbi.abtProtocolInfo[1] & 0xf0) >> 4)]);
|
||||
}
|
||||
if((nbi.abtProtocolInfo[1] & 0x0f) == PI_ISO14443_4_SUPPORTED) {
|
||||
printf ("* Protocol types supported: ISO/IEC 14443-4\n");
|
||||
}
|
||||
printf ("* Frame Waiting Time: %.4g ms\n",256.0*16.0*(1<<((nbi.abtProtocolInfo[2] & 0xf0) >> 4))/13560.0);
|
||||
if((nbi.abtProtocolInfo[2] & (PI_NAD_SUPPORTED|PI_CID_SUPPORTED)) != 0) {
|
||||
printf ("* Frame options supported: ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_NAD_SUPPORTED) != 0) printf ("NAD ");
|
||||
if ((nbi.abtProtocolInfo[2] & PI_CID_SUPPORTED) != 0) printf ("CID ");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose)
|
||||
{
|
||||
(void) verbose;
|
||||
printf (" NFCID3: ");
|
||||
print_hex (ndi.abtNFCID3, 10);
|
||||
printf (" BS: %02x\n", ndi.btBS);
|
||||
printf (" BR: %02x\n", ndi.btBR);
|
||||
printf (" TO: %02x\n", ndi.btTO);
|
||||
printf (" PP: %02x\n", ndi.btPP);
|
||||
if (ndi.szGB) {
|
||||
printf ("General Bytes: ");
|
||||
print_hex (ndi.abtGB, ndi.szGB);
|
||||
}
|
||||
printf (" PARAMS: %02x %02x %02x %02x\n", nbi.btParam1, nbi.btParam2, nbi.btParam3, nbi.btParam4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +628,7 @@ print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi)
|
||||
* @return Returns the list of found device descriptions.
|
||||
*/
|
||||
nfc_device_desc_t *
|
||||
parse_device_desc (int argc, const char *argv[], size_t * szFound)
|
||||
parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose)
|
||||
{
|
||||
nfc_device_desc_t *pndd = 0;
|
||||
int arg;
|
||||
@@ -162,7 +638,7 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound)
|
||||
for (arg = 1; arg < argc; arg++) {
|
||||
|
||||
if (0 == strcmp (argv[arg], "--device")) {
|
||||
|
||||
// FIXME: this device selection by command line options is terrible & does not support USB/PCSC drivers
|
||||
if (argc > arg + 1) {
|
||||
char buffer[256];
|
||||
|
||||
@@ -182,10 +658,64 @@ parse_device_desc (int argc, const char *argv[], size_t * szFound)
|
||||
sscanf (strtok (NULL, ":"), "%u", &pndd->uiSpeed);
|
||||
|
||||
*szFound = 1;
|
||||
} else {
|
||||
errx (1, "usage: %s [--device driver:port:speed]", argv[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((0 == strcmp (argv[arg], "-v")) || (0 == strcmp (argv[arg], "--verbose"))) {
|
||||
*verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
return pndd;
|
||||
}
|
||||
|
||||
const char *
|
||||
str_nfc_baud_rate (const nfc_baud_rate_t nbr)
|
||||
{
|
||||
switch(nbr) {
|
||||
case NBR_UNDEFINED:
|
||||
return "undefined baud rate";
|
||||
break;
|
||||
case NBR_106:
|
||||
return "106 kbps";
|
||||
break;
|
||||
case NBR_212:
|
||||
return "212 kbps";
|
||||
break;
|
||||
case NBR_424:
|
||||
return "424 kbps";
|
||||
break;
|
||||
case NBR_847:
|
||||
return "847 kbps";
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
print_nfc_target (const nfc_target_t nt, bool verbose)
|
||||
{
|
||||
switch(nt.nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
printf ("ISO/IEC 14443A (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443a_info (nt.nti.nai, verbose);
|
||||
break;
|
||||
case NMT_JEWEL:
|
||||
printf ("Innovision Jewel (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_jewel_info (nt.nti.nji, verbose);
|
||||
break;
|
||||
case NMT_FELICA:
|
||||
printf ("FeliCa (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_felica_info (nt.nti.nfi, verbose);
|
||||
break;
|
||||
case NMT_ISO14443B:
|
||||
printf ("ISO/IEC 14443-4B (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_iso14443b_info (nt.nti.nbi, verbose);
|
||||
break;
|
||||
case NMT_DEP:
|
||||
printf ("D.E.P. (%s) target:\n", str_nfc_baud_rate(nt.nm.nbr));
|
||||
print_nfc_dep_info (nt.nti.ndi, verbose);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library examples
|
||||
*
|
||||
* Copyright (C) 2010, Romuald Conty
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* Copyright (C) 2010, Romuald Conty, Romain Tartière
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1) Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2 )Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Note that this license only applies on the examples, NFC library itself is under LGPL
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-utils.h
|
||||
* @brief Provide some examples shared functions like print, parity calculation, options parsing.
|
||||
*/
|
||||
@@ -26,6 +38,46 @@
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <err.h>
|
||||
|
||||
/**
|
||||
* @macro DBG
|
||||
* @brief Print a message of standard output only in DEBUG mode
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define DBG(...) do { \
|
||||
warnx ("DBG %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define DBG(...) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macro WARN
|
||||
* @brief Print a warn message
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define WARN(...) do { \
|
||||
warnx ("WARNING %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define WARN(...) warnx ("WARNING: " __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macro ERR
|
||||
* @brief Print a error message
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
# define ERR(...) do { \
|
||||
warnx ("ERROR %s:%d", __FILE__, __LINE__); \
|
||||
warnx (" " __VA_ARGS__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
# define ERR(...) warnx ("ERROR: " __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
byte_t oddparity (const byte_t bt);
|
||||
void oddparity_byte_ts (const byte_t * pbtData, const size_t szLen, byte_t * pbtPar);
|
||||
@@ -34,10 +86,14 @@ void print_hex (const byte_t * pbtData, const size_t szLen);
|
||||
void print_hex_bits (const byte_t * pbtData, const size_t szBits);
|
||||
void print_hex_par (const byte_t * pbtData, const size_t szBits, const byte_t * pbtDataPar);
|
||||
|
||||
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai);
|
||||
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi);
|
||||
void print_nfc_felica_info (const nfc_felica_info_t nfi);
|
||||
void print_nfc_iso14443a_info (const nfc_iso14443a_info_t nai, bool verbose);
|
||||
void print_nfc_iso14443b_info (const nfc_iso14443b_info_t nbi, bool verbose);
|
||||
void print_nfc_felica_info (const nfc_felica_info_t nfi, bool verbose);
|
||||
void print_nfc_jewel_info (const nfc_jewel_info_t nji, bool verbose);
|
||||
void print_nfc_dep_info (const nfc_dep_info_t ndi, bool verbose);
|
||||
|
||||
nfc_device_desc_t *parse_device_desc (int argc, const char *argv[], size_t * szFound);
|
||||
void print_nfc_target (const nfc_target_t nt, bool verbose);
|
||||
|
||||
nfc_device_desc_t *parse_args (int argc, const char *argv[], size_t * szFound, bool * verbose);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user