libfreefare/examples/mifare-classic-format.c

263 lines
6.2 KiB
C
Raw Normal View History

#if defined(HAVE_CONFIG_H)
2017-06-29 12:25:53 +02:00
#include "config.h"
#endif
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nfc/nfc.h>
#include <freefare.h>
2010-07-01 15:25:14 +02:00
#define START_FORMAT_N "Formatting %d sectors ["
#define DONE_FORMAT "] done.\n"
2010-06-26 13:57:25 +02:00
MifareClassicKey default_keys[40];
MifareClassicKey default_keys_int[] = {
2017-06-27 13:58:31 +02:00
{ 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 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
2017-06-27 13:58:31 +02:00
int format_mifare_classic_1k(FreefareTag tag);
int format_mifare_classic_4k(FreefareTag tag);
int try_format_sector(FreefareTag tag, MifareClassicSectorNumber sector);
static int at_block = 0;
static int mod_block = 10;
2010-06-26 13:57:25 +02:00
struct {
bool fast;
bool interactive;
} format_options = {
.fast = false,
.interactive = true
};
static void
2017-06-27 13:58:31 +02:00
display_progress(void)
2010-06-26 13:57:25 +02:00
{
at_block++;
if (0 == (at_block % mod_block)) {
2017-06-27 13:58:31 +02:00
printf("%d", at_block);
fflush(stdout);
} else {
2017-06-27 13:58:31 +02:00
printf(".");
fflush(stdout);
2010-06-26 13:57:25 +02:00
}
}
int
2017-06-27 13:58:31 +02:00
format_mifare_classic_1k(FreefareTag tag)
{
2017-06-27 13:58:31 +02:00
printf(START_FORMAT_N, 16);
for (int sector = 0; sector < 16; sector++) {
2017-06-27 13:58:31 +02:00
if (!try_format_sector(tag, sector))
return 0;
}
2017-06-27 13:58:31 +02:00
printf(DONE_FORMAT);
return 1;
}
int
2017-06-27 13:58:31 +02:00
format_mifare_classic_4k(FreefareTag tag)
{
2017-06-27 13:58:31 +02:00
printf(START_FORMAT_N, 32 + 8);
for (int sector = 0; sector < (32 + 8); sector++) {
2017-06-27 13:58:31 +02:00
if (!try_format_sector(tag, sector))
return 0;
}
2017-06-27 13:58:31 +02:00
printf(DONE_FORMAT);
return 1;
}
int
2017-06-27 13:58:31 +02:00
try_format_sector(FreefareTag tag, MifareClassicSectorNumber sector)
{
2017-06-27 13:58:31 +02:00
display_progress();
for (size_t i = 0; i < (sizeof(default_keys) / sizeof(MifareClassicKey)); i++) {
MifareClassicBlockNumber block = mifare_classic_sector_last_block(sector);
if ((0 == mifare_classic_connect(tag)) && (0 == mifare_classic_authenticate(tag, block, default_keys[i], MFC_KEY_A))) {
if (0 == mifare_classic_format_sector(tag, sector)) {
mifare_classic_disconnect(tag);
return 1;
} else if (EIO == errno) {
2017-06-27 13:58:31 +02:00
err(EXIT_FAILURE, "sector %d", sector);
}
2017-06-27 13:58:31 +02:00
mifare_classic_disconnect(tag);
}
2017-06-27 13:58:31 +02:00
if ((0 == mifare_classic_connect(tag)) && (0 == mifare_classic_authenticate(tag, block, default_keys[i], MFC_KEY_B))) {
if (0 == mifare_classic_format_sector(tag, sector)) {
mifare_classic_disconnect(tag);
return 1;
} else if (EIO == errno) {
2017-06-27 13:58:31 +02:00
err(EXIT_FAILURE, "sector %d", sector);
}
2017-06-27 13:58:31 +02:00
mifare_classic_disconnect(tag);
}
}
2017-06-27 13:58:31 +02:00
warnx("No known authentication key for sector %d", sector);
return 0;
}
static void
usage(char *progname)
{
2017-06-27 13:58:31 +02:00
fprintf(stderr, "usage: %s [-fy] [keyfile]\n", progname);
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, " -f Fast format (only erase MAD)\n");
fprintf(stderr, " -y Do not ask for confirmation (dangerous)\n");
fprintf(stderr, " keyfile Use keys from dump in addition to internal default keys\n");
}
int
main(int argc, char *argv[])
{
int ch;
int error = EXIT_SUCCESS;
2012-01-25 10:58:16 +01:00
nfc_device *device = NULL;
FreefareTag *tags = NULL;
2017-06-27 13:58:31 +02:00
while ((ch = getopt(argc, argv, "fhy")) != -1) {
switch (ch) {
case 'f':
format_options.fast = true;
break;
case 'h':
usage(argv[0]);
2017-06-27 13:58:31 +02:00
exit(EXIT_SUCCESS);
break;
case 'y':
format_options.interactive = false;
break;
default:
usage(argv[0]);
2017-06-27 13:58:31 +02:00
exit(EXIT_FAILURE);
}
}
// Remaining args, if any, are in argv[optind .. (argc-1)]
2015-05-12 13:19:00 +02:00
memcpy(default_keys, default_keys_int, sizeof(default_keys_int));
2017-06-27 13:58:31 +02:00
if ((argc - optind) > 0) {
int i, rc;
char kbuffer[1024] = {0};
memset(kbuffer, 0, sizeof kbuffer);
FILE *fp = fopen(argv[optind], "rb");
if (fp == NULL)
errx(EXIT_FAILURE, "Unable to open file");
for (i = 0; (rc = getc(fp)) != EOF && i < 1024; kbuffer[i++] = rc) { }
fclose(fp);
i = sizeof(default_keys_int) / 6;
for (int s = 0; s < 16; s++) {
int startblock = s * 4;
int pos_a = (startblock + 3) * 16;
int pos_b = (startblock + 3) * 16 + 10;
memcpy((default_keys + i++), kbuffer + pos_a, 6);
memcpy((default_keys + i++), kbuffer + pos_b, 6);
}
}
2012-01-25 10:58:16 +01:00
nfc_connstring devices[8];
2010-06-26 15:48:25 +02:00
size_t device_count;
nfc_context *context;
2017-06-27 13:58:31 +02:00
nfc_init(&context);
if (context == NULL)
errx(EXIT_FAILURE, "Unable to init libnfc (malloc)");
2017-06-27 13:58:31 +02:00
device_count = nfc_list_devices(context, devices, 8);
2012-01-25 10:58:16 +01:00
if (device_count <= 0)
2017-06-27 13:58:31 +02:00
errx(EXIT_FAILURE, "No NFC device found.");
for (size_t d = 0; d < device_count; d++) {
2017-06-27 13:58:31 +02:00
device = nfc_open(context, devices[d]);
if (!device) {
2017-06-27 13:58:31 +02:00
warnx("nfc_open() failed.");
error = EXIT_FAILURE;
continue;
}
2017-06-27 13:58:31 +02:00
tags = freefare_get_tags(device);
if (!tags) {
2017-06-27 13:58:31 +02:00
nfc_close(device);
errx(EXIT_FAILURE, "Error listing Mifare Classic tag.");
}
for (int i = 0; (!error) && tags[i]; i++) {
2017-06-27 13:58:31 +02:00
switch (freefare_get_tag_type(tags[i])) {
case MIFARE_CLASSIC_1K:
case MIFARE_CLASSIC_4K:
break;
default:
continue;
}
2017-06-27 13:58:31 +02:00
char *tag_uid = freefare_get_tag_uid(tags[i]);
char buffer[BUFSIZ];
2017-06-27 13:58:31 +02:00
printf("Found %s with UID %s. ", freefare_get_tag_friendly_name(tags[i]), tag_uid);
bool format = true;
if (format_options.interactive) {
2017-06-27 13:58:31 +02:00
printf("Format [yN] ");
fgets(buffer, BUFSIZ, stdin);
format = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
} else {
2017-06-27 13:58:31 +02:00
printf("\n");
}
if (format) {
2017-06-27 13:58:31 +02:00
enum freefare_tag_type tt = freefare_get_tag_type(tags[i]);
at_block = 0;
if (format_options.fast) {
2017-06-27 13:58:31 +02:00
printf(START_FORMAT_N, (tt == MIFARE_CLASSIC_1K) ? 1 : 2);
if (!try_format_sector(tags[i], 0x00))
break;
if (tt == MIFARE_CLASSIC_4K)
2017-06-27 13:58:31 +02:00
if (!try_format_sector(tags[i], 0x10))
break;
2017-06-27 13:58:31 +02:00
printf(DONE_FORMAT);
continue;
}
switch (tt) {
case MIFARE_CLASSIC_1K:
mod_block = 4;
2017-06-27 13:58:31 +02:00
if (!format_mifare_classic_1k(tags[i]))
error = 1;
break;
case MIFARE_CLASSIC_4K:
mod_block = 10;
2017-06-27 13:58:31 +02:00
if (!format_mifare_classic_4k(tags[i]))
error = 1;
break;
default:
/* Keep compiler quiet */
break;
}
}
2017-06-27 13:58:31 +02:00
free(tag_uid);
}
2017-06-27 13:58:31 +02:00
freefare_free_tags(tags);
nfc_close(device);
}
2017-06-27 13:58:31 +02:00
nfc_exit(context);
exit(error);
}