nfc-mfclassic.c 20.9 KB
Newer Older
1
/*-
2
 * Free/Libre Near Field Communication (NFC) library
3
 *
4 5 6 7 8 9
 * Libnfc historical contributors:
 * Copyright (C) 2009      Roel Verdult
 * Copyright (C) 2009-2013 Romuald Conty
 * Copyright (C) 2010-2012 Romain Tartière
 * Copyright (C) 2010-2013 Philippe Teuwen
 * Copyright (C) 2012-2013 Ludovic Rousseau
10
 * See AUTHORS file for a more comprehensive list of contributors.
11 12
 * Additional contributors of this file:
 * Copyright (C) 2011      Adam Laurie
13
 *
14 15 16
 * 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,
17
 *  this list of conditions and the following disclaimer.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *  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.
33
 *
34
 * Note that this license only applies on the examples, NFC library itself is under LGPL
35
 *
36 37 38 39 40
 */

/**
 * @file nfc-mfclassic.c
 * @brief MIFARE Classic manipulation example
41
 */
Roel Verdult's avatar
Roel Verdult committed
42

43
#ifdef HAVE_CONFIG_H
44
#  include "config.h"
45 46
#endif // HAVE_CONFIG_H

Roel Verdult's avatar
Roel Verdult committed
47 48
#include <stdio.h>
#include <stdlib.h>
49
#include <stdint.h>
50
#include <stddef.h>
51
#include <stdbool.h>
52

Roel Verdult's avatar
Roel Verdult committed
53 54 55
#include <string.h>
#include <ctype.h>

56
#include <nfc/nfc.h>
57

58
#include "mifare.h"
59
#include "nfc-utils.h"
Roel Verdult's avatar
Roel Verdult committed
60

61
static nfc_context *context;
62 63
static nfc_device *pnd;
static nfc_target nt;
Roel Verdult's avatar
Roel Verdult committed
64
static mifare_param mp;
65 66
static mifare_classic_tag mtKeys;
static mifare_classic_tag mtDump;
Roel Verdult's avatar
Roel Verdult committed
67
static bool bUseKeyA;
Roel Verdult's avatar
Roel Verdult committed
68
static bool bUseKeyFile;
69
static bool bForceKeyFile;
70
static bool bTolerateFailures;
71
static bool magic2 = false;
72
static uint8_t uiBlocks;
73
static uint8_t keys[] = {
74 75 76 77 78 79 80
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7,
  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
  0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd,
  0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a,
  0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
Roel Verdult's avatar
Roel Verdult committed
81
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Roel Verdult's avatar
Roel Verdult committed
82
  0xab, 0xcd, 0xef, 0x12, 0x34, 0x56
Roel Verdult's avatar
Roel Verdult committed
83
};
Roel Verdult's avatar
Roel Verdult committed
84

85
static const nfc_modulation nmMifare = {
86 87 88 89
  .nmt = NMT_ISO14443A,
  .nbr = NBR_106,
};

90
static size_t num_keys = sizeof(keys) / 6;
91

92 93
#define MAX_FRAME_LEN 264

94
static uint8_t abtRx[MAX_FRAME_LEN];
95
static int szRxBits;
96

97
uint8_t  abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 };
98 99

// special unlock command
100 101
uint8_t  abtUnlock1[1] = { 0x40 };
uint8_t  abtUnlock2[1] = { 0x43 };
102 103

static  bool
104
transmit_bits(const uint8_t *pbtTx, const size_t szTxBits)
105 106
{
  // Show transmitted command
107 108
  printf("Sent bits:     ");
  print_hex_bits(pbtTx, szTxBits);
109
  // Transmit the bit frame command, we don't use the arbitrary parity feature
110
  if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0)
111 112 113
    return false;

  // Show received answer
114 115
  printf("Received bits: ");
  print_hex_bits(abtRx, szRxBits);
116 117 118 119 120 121
  // Succesful transfer
  return true;
}


static  bool
122
transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
123 124
{
  // Show transmitted command
125 126
  printf("Sent bits:     ");
  print_hex(pbtTx, szTx);
127
  // Transmit the command bytes
128
  int res;
129
  if ((res = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0)
130 131 132
    return false;

  // Show received answer
133 134
  printf("Received bits: ");
  print_hex(abtRx, res);
135 136 137 138
  // Succesful transfer
  return true;
}

139
static void
140
print_success_or_failure(bool bFailure, uint32_t *uiBlockCounter)
141
{
142
  printf("%c", (bFailure) ? 'x' : '.');
143
  if (uiBlockCounter && !bFailure)
144
    *uiBlockCounter += 1;
145 146
}

147
static  bool
148
is_first_block(uint32_t uiBlock)
Roel Verdult's avatar
Roel Verdult committed
149 150
{
  // Test if we are in the small or big sectors
151 152 153 154
  if (uiBlock < 128)
    return ((uiBlock) % 4 == 0);
  else
    return ((uiBlock) % 16 == 0);
Roel Verdult's avatar
Roel Verdult committed
155 156
}

157
static  bool
158
is_trailer_block(uint32_t uiBlock)
Roel Verdult's avatar
Roel Verdult committed
159 160
{
  // Test if we are in the small or big sectors
161 162 163 164
  if (uiBlock < 128)
    return ((uiBlock + 1) % 4 == 0);
  else
    return ((uiBlock + 1) % 16 == 0);
Roel Verdult's avatar
Roel Verdult committed
165 166
}

167
static  uint32_t
168
get_trailer_block(uint32_t uiFirstBlock)
Roel Verdult's avatar
Roel Verdult committed
169 170
{
  // Test if we are in the small or big sectors
171 172 173 174 175 176 177
  uint32_t trailer_block = 0;
  if (uiFirstBlock < 128) {
    trailer_block = uiFirstBlock + (3 - (uiFirstBlock % 4));
  } else {
    trailer_block = uiFirstBlock + (15 - (uiFirstBlock % 16));
  }
  return trailer_block;
Roel Verdult's avatar
Roel Verdult committed
178 179
}

180
static  bool
181
authenticate(uint32_t uiBlock)
Roel Verdult's avatar
Roel Verdult committed
182 183 184
{
  mifare_cmd mc;
  uint32_t uiTrailerBlock;
185

186
  // Set the authentication information (uid)
187
  memcpy(mp.mpa.abtAuthUid, nt.nti.nai.abtUid + nt.nti.nai.szUidLen - 4, 4);
188 189 190 191

  // Should we use key A or B?
  mc = (bUseKeyA) ? MC_AUTH_A : MC_AUTH_B;

Roel Verdult's avatar
Roel Verdult committed
192
  // Key file authentication.
193
  if (bUseKeyFile) {
Roel Verdult's avatar
Roel Verdult committed
194 195

    // Locate the trailer (with the keys) used for this sector
196
    uiTrailerBlock = get_trailer_block(uiBlock);
197

198 199
    // Extract the right key from dump file
    if (bUseKeyA)
200
      memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6);
201
    else
202
      memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6);
Roel Verdult's avatar
Roel Verdult committed
203 204

    // Try to authenticate for the current sector
205
    if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp))
206
      return true;
207 208
  } else {
    // Try to guess the right key
209
    for (size_t key_index = 0; key_index < num_keys; key_index++) {
210 211
      memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6);
      if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) {
Roel Verdult's avatar
Roel Verdult committed
212
        if (bUseKeyA)
213
          memcpy(mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6);
Roel Verdult's avatar
Roel Verdult committed
214
        else
215
          memcpy(mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6);
Roel Verdult's avatar
Roel Verdult committed
216 217
        return true;
      }
218
      nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL);
Roel Verdult's avatar
Roel Verdult committed
219 220
    }
  }
221

Roel Verdult's avatar
Roel Verdult committed
222 223 224
  return false;
}

225
static bool
226
unlock_card(void)
227
{
228 229 230 231
  if (magic2) {
    printf("Don't use R/W with this card, this is not required!\n");
    return false;
  }
232 233

  // Configure the CRC
234 235
  if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) {
    nfc_perror(pnd, "nfc_configure");
236
    return false;
237 238
  }
  // Use raw send/receive methods
239 240
  if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
    nfc_perror(pnd, "nfc_configure");
241
    return false;
242 243 244
  }

  iso14443a_crc_append(abtHalt, 2);
245
  transmit_bytes(abtHalt, 4);
246
  // now send unlock
247
  if (!transmit_bits(abtUnlock1, 7)) {
248 249 250
    printf("unlock failure!\n");
    return false;
  }
251
  if (!transmit_bytes(abtUnlock2, 1)) {
252 253 254 255 256 257
    printf("unlock failure!\n");
    return false;
  }

  // reset reader
  // Configure the CRC
258 259
  if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) {
    nfc_perror(pnd, "nfc_device_set_property_bool");
260
    return false;
261 262
  }
  // Switch off raw send/receive methods
263 264
  if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) {
    nfc_perror(pnd, "nfc_device_set_property_bool");
265
    return false;
266 267 268 269
  }
  return true;
}

270 271 272 273 274 275 276 277 278 279 280 281 282
static int
get_rats(void)
{
  int res;
  uint8_t  abtRats[2] = { 0xe0, 0x50};
  // Use raw send/receive methods
  if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) {
    nfc_perror(pnd, "nfc_configure");
    return -1;
  }
  res = nfc_initiator_transceive_bytes(pnd, abtRats, sizeof(abtRats), abtRx, sizeof(abtRx), 0);
  if (res > 0) {
    // ISO14443-4 card, turn RF field off/on to access ISO14443-3 again
283 284 285 286 287 288 289 290
    if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false) < 0) {
      nfc_perror(pnd, "nfc_configure");
      return -1;
    }
    if (nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true) < 0) {
      nfc_perror(pnd, "nfc_configure");
      return -1;
    }
291 292 293 294 295 296 297 298 299 300 301
  }
  // Reselect tag
  if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
    printf("Error: tag disappeared\n");
    nfc_close(pnd);
    nfc_exit(context);
    exit(EXIT_FAILURE);
  }
  return res;
}

302
static  bool
303
read_card(int read_unlocked)
Roel Verdult's avatar
Roel Verdult committed
304
{
305
  int32_t iBlock;
306
  bool    bFailure = false;
307
  uint32_t uiReadBlocks = 0;
Roel Verdult's avatar
Roel Verdult committed
308

309
  if (read_unlocked)
310 311 312
    if (!unlock_card())
      return false;

313
  printf("Reading out %d blocks |", uiBlocks + 1);
Roel Verdult's avatar
Roel Verdult committed
314
  // Read the card from end to begin
315
  for (iBlock = uiBlocks; iBlock >= 0; iBlock--) {
Roel Verdult's avatar
Roel Verdult committed
316
    // Authenticate everytime we reach a trailer block
317
    if (is_trailer_block(iBlock)) {
318
      if (bFailure) {
Roel Verdult's avatar
Roel Verdult committed
319
        // When a failure occured we need to redo the anti-collision
320
        if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
321
          printf("!\nError: tag was removed\n");
322
          return false;
Roel Verdult's avatar
Roel Verdult committed
323 324 325
        }
        bFailure = false;
      }
326

327
      fflush(stdout);
328

Roel Verdult's avatar
Roel Verdult committed
329
      // Try to authenticate for the current sector
330 331
      if (!read_unlocked && !authenticate(iBlock)) {
        printf("!\nError: authentication failed for block 0x%02x\n", iBlock);
Roel Verdult's avatar
Roel Verdult committed
332 333 334
        return false;
      }
      // Try to read out the trailer
335 336 337
      if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) {
        if (read_unlocked) {
          memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
338 339
        } else {
          // Copy the keys over from our key dump and store the retrieved access bits
340 341 342
          memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, 6);
          memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4);
          memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6);
343
        }
344
      } else {
345 346
        printf("!\nfailed to read trailer block 0x%02x\n", iBlock);
        bFailure = true;
Roel Verdult's avatar
Roel Verdult committed
347 348 349
      }
    } else {
      // Make sure a earlier readout did not fail
350
      if (!bFailure) {
Roel Verdult's avatar
Roel Verdult committed
351
        // Try to read out the data block
352 353
        if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) {
          memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16);
Roel Verdult's avatar
Roel Verdult committed
354
        } else {
355
          printf("!\nError: unable to read block 0x%02x\n", iBlock);
356
          bFailure = true;
Roel Verdult's avatar
Roel Verdult committed
357 358 359
        }
      }
    }
360 361 362 363
    // Show if the readout went well for each block
    print_success_or_failure(bFailure, &uiReadBlocks);
    if ((! bTolerateFailures) && bFailure)
      return false;
Roel Verdult's avatar
Roel Verdult committed
364
  }
365 366 367
  printf("|\n");
  printf("Done, %d of %d blocks read.\n", uiReadBlocks, uiBlocks + 1);
  fflush(stdout);
Roel Verdult's avatar
Roel Verdult committed
368 369 370 371

  return true;
}

372
static  bool
373
write_card(int write_block_zero)
Roel Verdult's avatar
Roel Verdult committed
374
{
375
  uint32_t uiBlock;
376
  bool    bFailure = false;
377
  uint32_t uiWriteBlocks = 0;
Roel Verdult's avatar
Roel Verdult committed
378

379
  if (write_block_zero)
380
    if (!unlock_card())
381 382
      return false;

383
  printf("Writing %d blocks |", uiBlocks + 1);
Roel Verdult's avatar
Roel Verdult committed
384
  // Write the card from begin to end;
385
  for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) {
Roel Verdult's avatar
Roel Verdult committed
386
    // Authenticate everytime we reach the first sector of a new block
387
    if (is_first_block(uiBlock)) {
388
      if (bFailure) {
Roel Verdult's avatar
Roel Verdult committed
389
        // When a failure occured we need to redo the anti-collision
390
        if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
391
          printf("!\nError: tag was removed\n");
Roel Verdult's avatar
Roel Verdult committed
392 393 394 395
          return false;
        }
        bFailure = false;
      }
396

397
      fflush(stdout);
Roel Verdult's avatar
Roel Verdult committed
398 399

      // Try to authenticate for the current sector
400 401
      if (!write_block_zero && !authenticate(uiBlock)) {
        printf("!\nError: authentication failed for block %02x\n", uiBlock);
Roel Verdult's avatar
Roel Verdult committed
402 403 404
        return false;
      }
    }
405

406
    if (is_trailer_block(uiBlock)) {
Roel Verdult's avatar
Roel Verdult committed
407
      // Copy the keys over from our key dump and store the retrieved access bits
408 409 410
      memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6);
      memcpy(mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4);
      memcpy(mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6);
Roel Verdult's avatar
Roel Verdult committed
411 412

      // Try to write the trailer
413 414
      if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) {
        printf("failed to write trailer block %d \n", uiBlock);
415 416
        bFailure = true;
      }
Roel Verdult's avatar
Roel Verdult committed
417 418
    } else {
      // The first block 0x00 is read only, skip this
419
      if (uiBlock == 0 && ! write_block_zero && ! magic2)
420
        continue;
Roel Verdult's avatar
Roel Verdult committed
421

422

Roel Verdult's avatar
Roel Verdult committed
423
      // Make sure a earlier write did not fail
424
      if (!bFailure) {
Roel Verdult's avatar
Roel Verdult committed
425
        // Try to write the data block
426
        memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16);
427 428
        // do not write a block 0 with incorrect BCC - card will be made invalid!
        if (uiBlock == 0) {
429
          if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) {
430
            printf("!\nError: incorrect BCC in MFD file!\n");
431
            printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]);
432 433 434
            return false;
          }
        }
435
        if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp))
436
          bFailure = true;
Roel Verdult's avatar
Roel Verdult committed
437 438
      }
    }
439 440 441 442
    // Show if the write went well for each block
    print_success_or_failure(bFailure, &uiWriteBlocks);
    if ((! bTolerateFailures) && bFailure)
      return false;
Roel Verdult's avatar
Roel Verdult committed
443
  }
444 445 446
  printf("|\n");
  printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1);
  fflush(stdout);
447

Roel Verdult's avatar
Roel Verdult committed
448 449 450
  return true;
}

451
typedef enum {
452 453
  ACTION_READ,
  ACTION_WRITE,
454
  ACTION_USAGE
455 456
} action_t;

457
static void
458
print_usage(const char *pcProgramName)
459
{
460
  printf("Usage: ");
461
  printf("%s r|R|w|W a|b <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName);
462 463 464 465
  printf("  r|R|w|W       - Perform read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n");
  printf("                  *** note that unlocked write will attempt to overwrite block 0 including UID\n");
  printf("                  *** unlocked read does not require authentication and will reveal A and B keys\n");
  printf("                  *** unlocking only works with special Mifare 1K cards (Chinese clones)\n");
466
  printf("  a|A|b|B       - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n");
467 468
  printf("  <dump.mfd>    - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n");
  printf("  <keys.mfd>    - MiFare Dump (MFD) that contain the keys (optional)\n");
469
  printf("  f             - Force using the keyfile even if UID does not match (optional)\n");
470 471
}

472
int
473
main(int argc, const char *argv[])
474
{
475
  action_t atAction = ACTION_USAGE;
476
  uint8_t *pbtUID;
477
  int    unlock = 0;
478

479
  if (argc < 2) {
480 481
    print_usage(argv[0]);
    exit(EXIT_FAILURE);
Roel Verdult's avatar
Roel Verdult committed
482
  }
483
  const char *command = argv[1];
Roel Verdult's avatar
Roel Verdult committed
484

485
  if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) {
486
    if (argc < 4) {
487 488
      print_usage(argv[0]);
      exit(EXIT_FAILURE);
489
    }
490
    atAction = ACTION_READ;
491
    if (strcmp(command, "R") == 0)
492
      unlock = 1;
493
    bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
494
    bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
495
    bUseKeyFile = (argc > 4);
496
    bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0));
497
  } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0) {
498
    if (argc < 4) {
499 500
      print_usage(argv[0]);
      exit(EXIT_FAILURE);
501
    }
502
    atAction = ACTION_WRITE;
503
    if (strcmp(command, "W") == 0)
504
      unlock = 1;
505
    bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a';
506
    bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2]));
507
    bUseKeyFile = (argc > 4);
508
    bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0));
Roel Verdult's avatar
Roel Verdult committed
509 510
  }

511 512 513 514
  if (atAction == ACTION_USAGE) {
    print_usage(argv[0]);
    exit(EXIT_FAILURE);
  }
515
  // We don't know yet the card size so let's read only the UID from the keyfile for the moment
516
  if (bUseKeyFile) {
517
    FILE *pfKeys = fopen(argv[4], "rb");
518 519
    if (pfKeys == NULL) {
      printf("Could not open keys file: %s\n", argv[4]);
520
      exit(EXIT_FAILURE);
521
    }
522 523
    if (fread(&mtKeys, 1, 4, pfKeys) != 4) {
      printf("Could not read UID from key file: %s\n", argv[4]);
524 525 526 527 528 529
      fclose(pfKeys);
      exit(EXIT_FAILURE);
    }
    fclose(pfKeys);
  }
  nfc_init(&context);
530 531 532 533
  if (context == NULL) {
    ERR("Unable to init libnfc (malloc)");
    exit(EXIT_FAILURE);
  }
534

535 536 537
// Try to open the NFC reader
  pnd = nfc_open(context, NULL);
  if (pnd == NULL) {
538
    ERR("Error opening NFC reader");
539 540 541
    nfc_exit(context);
    exit(EXIT_FAILURE);
  }
542

543 544 545 546 547 548
  if (nfc_initiator_init(pnd) < 0) {
    nfc_perror(pnd, "nfc_initiator_init");
    nfc_close(pnd);
    nfc_exit(context);
    exit(EXIT_FAILURE);
  };
549

550 551 552 553 554 555 556 557
// Let the reader only try once to find a tag
  if (nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false) < 0) {
    nfc_perror(pnd, "nfc_device_set_property_bool");
    nfc_close(pnd);
    nfc_exit(context);
    exit(EXIT_FAILURE);
  }
// Disable ISO14443-4 switching in order to read devices that emulate Mifare Classic with ISO14443-4 compliance.
558 559 560 561 562 563
  if (nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, false) < 0) {
    nfc_perror(pnd, "nfc_device_set_property_bool");
    nfc_close(pnd);
    nfc_exit(context);
    exit(EXIT_FAILURE);
  }
564

565
  printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
566

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
// Try to find a MIFARE Classic tag
  if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) {
    printf("Error: no tag was found\n");
    nfc_close(pnd);
    nfc_exit(context);
    exit(EXIT_FAILURE);
  }
// Test if we are dealing with a MIFARE compatible tag
  if ((nt.nti.nai.btSak & 0x08) == 0) {
    printf("Warning: tag is probably not a MFC!\n");
  }

// Get the info from the current tag
  pbtUID = nt.nti.nai.abtUid;

  if (bUseKeyFile) {
    uint8_t fileUid[4];
    memcpy(fileUid, mtKeys.amb[0].mbm.abtUID, 4);
// Compare if key dump UID is the same as the current tag UID, at least for the first 4 bytes
    if (memcmp(pbtUID, fileUid, 4) != 0) {
      printf("Expected MIFARE Classic card with UID starting as: %02x%02x%02x%02x\n",
             fileUid[0], fileUid[1], fileUid[2], fileUid[3]);
589 590
      printf("Got card with UID starting as:                     %02x%02x%02x%02x\n",
             pbtUID[0], pbtUID[1], pbtUID[2], pbtUID[3]);
591 592 593 594 595 596
      if (! bForceKeyFile) {
        printf("Aborting!\n");
        nfc_close(pnd);
        nfc_exit(context);
        exit(EXIT_FAILURE);
      }
597 598 599
    }
  }
  printf("Found MIFARE Classic card:\n");
600
  print_nfc_target(&nt, false);
601 602 603 604 605 606 607 608 609

// Guessing size
  if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02)
// 4K
    uiBlocks = 0xff;
  else if ((nt.nti.nai.btSak & 0x01) == 0x01)
// 320b
    uiBlocks = 0x13;
  else
610
// 1K/2K, checked through RATS
611
    uiBlocks = 0x3f;
612 613 614 615
// Testing RATS
  int res;
  if ((res = get_rats()) > 0) {
    if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05)
616 617
        && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f)
        && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) {
618 619 620
      // MIFARE Plus 2K
      uiBlocks = 0x7f;
    }
621 622 623 624 625
    // Chinese magic emulation card, ATS=0978009102:dabc1910
    if ((res == 9)  && (abtRx[5] == 0xda) && (abtRx[6] == 0xbc)
        && (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) {
      magic2 = true;
    }
626
  }
627 628
  printf("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16);

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
  if (bUseKeyFile) {
    FILE *pfKeys = fopen(argv[4], "rb");
    if (pfKeys == NULL) {
      printf("Could not open keys file: %s\n", argv[4]);
      exit(EXIT_FAILURE);
    }
    if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
      printf("Could not read keys file: %s\n", argv[4]);
      fclose(pfKeys);
      exit(EXIT_FAILURE);
    }
    fclose(pfKeys);
  }

  if (atAction == ACTION_READ) {
    memset(&mtDump, 0x00, sizeof(mtDump));
  } else {
    FILE *pfDump = fopen(argv[3], "rb");

    if (pfDump == NULL) {
      printf("Could not open dump file: %s\n", argv[3]);
      exit(EXIT_FAILURE);

    }

    if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) {
      printf("Could not read dump file: %s\n", argv[3]);
      fclose(pfDump);
      exit(EXIT_FAILURE);
    }
    fclose(pfDump);
  }
// printf("Successfully opened required files\n");

663 664 665 666
  if (atAction == ACTION_READ) {
    if (read_card(unlock)) {
      printf("Writing data to file: %s ...", argv[3]);
      fflush(stdout);
667
      FILE *pfDump = fopen(argv[3], "wb");
668 669
      if (pfDump == NULL) {
        printf("Could not open dump file: %s\n", argv[3]);
670
        nfc_close(pnd);
671
        nfc_exit(context);
672
        exit(EXIT_FAILURE);
673
      }
674
      if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) {
675 676 677 678 679
        printf("\nCould not write to file: %s\n", argv[3]);
        fclose(pfDump);
        nfc_close(pnd);
        nfc_exit(context);
        exit(EXIT_FAILURE);
680
      }
681 682 683 684 685 686
      printf("Done.\n");
      fclose(pfDump);
    }
  } else if (atAction == ACTION_WRITE) {
    write_card(unlock);
  }
687

688
  nfc_close(pnd);
689
  nfc_exit(context);
690
  exit(EXIT_SUCCESS);
Roel Verdult's avatar
Roel Verdult committed
691
}