diff --git a/src/mfoc.c b/src/mfoc.c index 6ff15e8..2aabd67 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -277,9 +277,12 @@ int main(int argc, char *const argv[]) if (trailer_block(block)) { if (!t.sectors[i].foundKeyA) { mc = MC_AUTH_A; - if (!nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) { - // fprintf(stdout, "!!Error: AUTH [Key A:%012llx] sector %02x t_block %02x\n", - // bytes_to_num(mp.mpa.abtKey, 6), i, block); + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_anticollision(t, r); } else { // Save all information about successfull keyA authentization @@ -289,9 +292,12 @@ int main(int argc, char *const argv[]) } if (!t.sectors[i].foundKeyB) { mc = MC_AUTH_B; - if (!nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) { - // fprintf(stdout, "!!Error: AUTH [Key B:%012llx] sector %02x t_block %02x\n", - // bytes_to_num(mp.mpa.abtKey, 6), i, block); + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_anticollision(t, r); // No success, try next block t.sectors[i].trailer = block; @@ -310,8 +316,6 @@ int main(int argc, char *const argv[]) fprintf(stdout, "."); } fflush(stdout); - // fprintf(stdout, "\nSuccess: AUTH [Key %c:%012llx] sector %02x t_block %02x\n", - // (mc == MC_AUTH_A ? 'A' :'B'), bytes_to_num(mp.mpa.abtKey, 6), i, block); // Save position of a trailer block to sector struct t.sectors[i++].trailer = block; } @@ -343,9 +347,12 @@ int main(int argc, char *const argv[]) for (uint32_t o = 0; o < bk->size; o++) { num_to_bytes(bk->brokenKeys[o], 6, mp.mpa.abtKey); mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; - if (!nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) { - // fprintf(stdout, "!!Error: AUTH [Key A:%012llx] sector %02x t_block %02x, key %d\n", - // bytes_to_num(mp.mpa.abtKey, 6), j, t.sectors[j].trailer, o); + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_anticollision(t, r); } else { // Save all information about successfull authentization @@ -398,9 +405,12 @@ int main(int argc, char *const argv[]) // Set required authetication method num_to_bytes(ck[i].key, 6, mp.mpa.abtKey); mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; - if (!nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) { - // fprintf(stdout, "!!Error: AUTH [Key A:%llx] sector %02x t_block %02x\n", - // bytes_to_num(mp.mpa.abtKey, 6), j, t.sectors[j].trailer); + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_anticollision(t, r); } else { // Save all information about successfull authentization @@ -457,12 +467,16 @@ 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)) { - // ERR ("Error: Auth A"); + int res; + if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_A, block, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_configure(r.pdi); mf_anticollision(t, r); } else { // and Read - if (nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) { + if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) { 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); @@ -470,22 +484,32 @@ int main(int argc, char *const argv[]) failure = false; } else { // Error, now try read() with B key - // ERR ("Error: Read A"); + if (res != NFC_ERFTRANS) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } 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)) { - // ERR ("Error: Auth B"); + if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mp)) < 0) { + if (res != NFC_EMFCAUTHFAIL) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_configure(r.pdi); mf_anticollision(t, r); } else { // and Read - if (nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) { + if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) { 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.nt)); failure = false; } else { + if (res != NFC_ERFTRANS) { + nfc_perror (r.pdi, "nfc_initiator_mifare_cmd"); + goto error; + } mf_configure(r.pdi); mf_anticollision(t, r); // ERR ("Error: Read B"); diff --git a/src/mifare.c b/src/mifare.c index 6c84724..ab04ac0 100644 --- a/src/mifare.c +++ b/src/mifare.c @@ -3,7 +3,7 @@ * * Copyright (C) 2009 Roel Verdult * Copyright (C) 2010 Romain Tartière - * Copyright (C) 2010, 2011 Romuald Conty + * Copyright (C) 2010, 2011, 2013 Romuald Conty * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,10 +28,23 @@ * Note that this license only applies on the examples, NFC library itself is under LGPL * */ + /** * @file mifare.c * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc */ + +/* + * This implementation was written based on information provided by the + * following document: + * + * MIFARE Classic Specification + * MF1ICS50 + * Functional specification + * Rev. 5.3 - 29 January 2008 + * http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf + */ + #include "mifare.h" #include @@ -39,25 +52,33 @@ #include /** - * @brief Execute a MIFARE Classic Command - * @return Returns true if action was successfully performed; otherwise returns false. + * @brief Execute a MIFARE Classic command + * @return Returns NFC_SUCCESS if action was successfully performed; otherwise returns error code (negative value). * @param pmp Some commands need additional information. This information should be supplied in the mifare_param union. * - * The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number. + * The specified MIFARE command will be executed on the tag. There are + * different commands possible, they all require the destination block number. + * * @note There are three different types of information (Authenticate, Data and Value). * * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. - * They are both used to initialize the internal cipher-state of the PN53X chip (http://libnfc.org/hardware/pn53x-chip). * After a successful authentication it will be possible to execute other commands (e.g. Read/Write). - * The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process. + * + * Like libnfc's functions, this one returns negative value on error (libnfc's + * error code) but two of them need a special attention in this context (MIFARE + * Classic): + * - NFC_EMFCAUTHFAIL, "MIFARE authentication failed", means key is not valid + * on specified sector. + * - NFC_ERFTRANS, "Invalid received frame", when occurs on MIFARE command + * read or write after a successful authentication, means permissions allowed + * by current acces bytes are not sufficient to process the command. */ -bool +int nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp) { uint8_t abtRx[265]; size_t szParamLen; uint8_t abtCmd[265]; - //bool bEasyFraming; abtCmd[0] = mc; // The MIFARE Classic command abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) @@ -89,7 +110,7 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8 // Please fix your code, you never should reach this statement default: - return false; + return NFC_EINVARG; break; } @@ -98,40 +119,23 @@ nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8 memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen); // FIXME: Save and restore bEasyFraming - // bEasyFraming = nfc_device_get_property_bool (pnd, NP_EASY_FRAMING, &bEasyFraming); - if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool"); - return false; + int res; + if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) { + return res; } // Fire the mifare command - int res; if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) { - if (res == NFC_ERFTRANS) { - // "Invalid received frame", 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 { - nfc_perror(pnd, "nfc_initiator_transceive_bytes"); - } - // XXX nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming); - return false; + return res; } - /* XXX - if (nfc_device_set_property_bool (pnd, NP_EASY_FRAMING, bEasyFraming) < 0) { - nfc_perror (pnd, "nfc_device_set_property_bool"); - return false; - } - */ // When we have executed a read command, copy the received bytes into the param if (mc == MC_READ) { if (res == 16) { memcpy(pmp->mpd.abtData, abtRx, 16); } else { - return false; + return NFC_EINVARG; } } // Command succesfully executed - return true; + return NFC_SUCCESS; } diff --git a/src/mifare.h b/src/mifare.h index fb90fea..0a4d2cb 100644 --- a/src/mifare.h +++ b/src/mifare.h @@ -3,7 +3,7 @@ * * Copyright (C) 2009 Roel Verdult * Copyright (C) 2010 Romain Tartière - * Copyright (C) 2010, 2011 Romuald Conty + * Copyright (C) 2010, 2011, 2013 Romuald Conty * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -35,12 +35,12 @@ */ #ifndef _LIBNFC_MIFARE_H_ -# define _LIBNFC_MIFARE_H_ +#define _LIBNFC_MIFARE_H_ -# include +#include // Compiler directive, set struct alignment to 1 uint8_t for compatibility -# pragma pack(1) +#pragma pack(1) typedef enum { MC_AUTH_A = 0x60, @@ -76,7 +76,7 @@ typedef union { // Reset struct alignment to default # pragma pack() -bool nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp); +int nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp); // Compiler directive, set struct alignment to 1 uint8_t for compatibility # pragma pack(1)