Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Added examples/mifare-desfire-ev1-change-picc-key #119

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ examples/mifare-classic-read-ndef
examples/mifare-classic-write-ndef
examples/mifare-desfire-access
examples/mifare-desfire-create-ndef
examples/mifare-desfire-ev1-change-picc-key
examples/mifare-desfire-ev1-configure-ats
examples/mifare-desfire-ev1-configure-default-key
examples/mifare-desfire-ev1-configure-random-uid
Expand All @@ -36,6 +37,7 @@ examples/mifare-desfire-info
examples/mifare-desfire-read-ndef
examples/mifare-desfire-write-ndef
examples/mifare-ultralight-info
examples/mifare-ultralightc-diversify
examples/ntag-detect
examples/ntag-removeauth
examples/ntag-setauth
Expand Down
4 changes: 4 additions & 0 deletions examples/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ bin_PROGRAMS = felica-lite-dump \
mifare-desfire-ev1-configure-ats \
mifare-desfire-ev1-configure-default-key \
mifare-desfire-ev1-configure-random-uid \
mifare-desfire-ev1-change-picc-key \
mifare-desfire-format \
mifare-desfire-info \
mifare-desfire-read-ndef \
Expand Down Expand Up @@ -49,6 +50,9 @@ mifare_desfire_ev1_configure_ats_LDADD = $(top_builddir)/libfreefare/libfreefare
mifare_desfire_ev1_configure_default_key_SOURCES = mifare-desfire-ev1-configure-default-key.c
mifare_desfire_ev1_configure_default_key_LDADD = $(top_builddir)/libfreefare/libfreefare.la

mifare_desfire_ev1_change_picc_key_SOURCES = mifare-desfire-ev1-change-picc-key.c
mifare_desfire_ev1_change_picc_key_LDADD = $(top_builddir)/libfreefare/libfreefare.la

mifare_desfire_ev1_configure_random_uid_SOURCES = mifare-desfire-ev1-configure-random-uid.c
mifare_desfire_ev1_configure_random_uid_LDADD = $(top_builddir)/libfreefare/libfreefare.la

Expand Down
252 changes: 252 additions & 0 deletions examples/mifare-desfire-ev1-change-picc-key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif

#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>

#include <nfc/nfc.h>

#include <freefare.h>

uint8_t null_key_data[8];

uint8_t new_key_version = 0x00;

MifareDESFireKey old_picc_key;
MifareDESFireKey new_picc_key;

#define NEW_KEY_VERSION new_key_version

struct {
bool interactive;
} configure_options = {
.interactive = true
};

static void
usage(char *progname)
{
fprintf(stderr, "usage: %s [-y]\n", progname);
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, " -y Do not ask for confirmation\n");
fprintf(stderr, " -k Existing PICC key (Default is all zeros)\n");
fprintf(stderr, " -n New PICC key (Default is all zeros)\n");
fprintf(stderr, " -v New PICC key version (default is zero)\n");
}

#define strnequal(x, y, n) (strncmp(x, y, n) == 0)

static inline bool
strhasprefix(const char* str, const char* prefix)
{
return strnequal(str, prefix, strlen(prefix));
}

MifareDESFireKey read_hex_desfire_key(const char* optarg)
{
uint8_t buffer[24];
int i;
uint64_t n;

bool is_des = true;

if (strhasprefix(optarg, "DES:")) {
is_des = true;
optarg += 4;
} else if (strhasprefix(optarg, "AES:")) {
is_des = false;
optarg += 4;
}

size_t len = strlen(optarg);
size_t div16 = len / 16;

if (div16 < 1 || div16 > 3 || (len % 16) != 0) {
fprintf(stderr,"Bad key length\n");
exit(EXIT_FAILURE);
}

if (div16 >= 1) {
n = strtoull(optarg, NULL, 16);
for (i = 7; i >= 0; i--) {
buffer[i] = (uint8_t) n;
n >>= 8;
}
}

if (div16 >= 2) {
n = strtoull(optarg+8, NULL, 16);
for (i = 7; i >= 0; i--) {
buffer[i+8] = (uint8_t) n;
n >>= 8;
}
}

if (div16 == 3) {
n = strtoull(optarg+16, NULL, 16);
for (i = 7; i >= 0; i--) {
buffer[i+16] = (uint8_t) n;
n >>= 8;
}
}

if (is_des && div16 == 1) {
return mifare_desfire_des_key_new(buffer);
}
if (is_des && div16 == 2) {
return mifare_desfire_3des_key_new(buffer);
}
if (is_des && div16 == 3) {
return mifare_desfire_3k3des_key_new(buffer);
}
if (!is_des && div16 == 2) {
return mifare_desfire_aes_key_new(buffer);
}
fprintf(stderr,"Bad key length\n");
exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
int ch;
int error = EXIT_SUCCESS;
nfc_device *device = NULL;
FreefareTag *tags = NULL;
bool should_diversify_new = false;

old_picc_key = mifare_desfire_des_key_new(null_key_data);
new_picc_key = mifare_desfire_des_key_new(null_key_data);

while ((ch = getopt(argc, argv, "hyk:n:v:D")) != -1) {
switch (ch) {
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
break;
case 'y':
configure_options.interactive = false;
break;
case 'k':
mifare_desfire_key_free(old_picc_key);
old_picc_key = read_hex_desfire_key(optarg);
break;
case 'n':
mifare_desfire_key_free(new_picc_key);
new_picc_key = read_hex_desfire_key(optarg);
break;
case 'v':
errno = 0;
new_key_version = (uint8_t)strtol(optarg, NULL, 0);
if (errno != 0) {
perror("strtol");
exit(EXIT_FAILURE);
}
break;
case 'D':
should_diversify_new = true;
break;
default:
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
// Remaining args, if any, are in argv[optind .. (argc-1)]

mifare_desfire_key_set_version(new_picc_key, new_key_version);

MifareKeyDeriver new_deriver = NULL;
if (should_diversify_new) {
new_deriver = mifare_key_deriver_new_an10922(new_picc_key, mifare_desfire_key_get_type(new_picc_key), AN10922_FLAG_DEFAULT);
}

nfc_connstring devices[8];
size_t device_count;

nfc_context *context;
nfc_init(&context);
if (context == NULL)
errx(EXIT_FAILURE, "Unable to init libnfc (malloc)");

device_count = nfc_list_devices(context, devices, 8);
if (device_count <= 0)
errx(EXIT_FAILURE, "No NFC device found.");

for (size_t d = 0; (!error) && (d < device_count); d++) {
device = nfc_open(context, devices[d]);
if (!device) {
warnx("nfc_open() failed.");
error = EXIT_FAILURE;
continue;
}

tags = freefare_get_tags(device);
if (!tags) {
nfc_close(device);
errx(EXIT_FAILURE, "Error listing Mifare DESFire tags.");
}

for (int i = 0; (!error) && tags[i]; i++) {
if (MIFARE_DESFIRE != freefare_get_tag_type(tags[i]))
continue;

char *tag_uid = freefare_get_tag_uid(tags[i]);
char buffer[BUFSIZ];

int res;

res = mifare_desfire_connect(tags[i]);
if (res < 0) {
warnx("Can't connect to Mifare DESFire target.");
error = EXIT_FAILURE;
break;
}

printf("Found %s with UID %s. ", freefare_get_tag_friendly_name(tags[i]), tag_uid);
bool do_it = true;

if (configure_options.interactive) {
printf("Change PICC key? [yN] ");
fgets(buffer, BUFSIZ, stdin);
do_it = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
} else {
printf("\n");
}

if (do_it) {

res = mifare_desfire_authenticate(tags[i], 0, old_picc_key);
if (res < 0) {
freefare_perror(tags[i], "mifare_desfire_authenticate");
error = EXIT_FAILURE;
break;
}

res = mifare_desfire_change_key(tags[i], 0, new_picc_key, old_picc_key);
if (res < 0) {
freefare_perror(tags[i], "mifare_desfire_change_key");
error = EXIT_FAILURE;
break;
}

}

mifare_desfire_disconnect(tags[i]);
free(tag_uid);
}

freefare_free_tags(tags);
nfc_close(device);
}

mifare_desfire_key_free(old_picc_key);
mifare_desfire_key_free(new_picc_key);

nfc_exit(context);
exit(error);
}
19 changes: 10 additions & 9 deletions libfreefare/freefare.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,15 @@ int mifare_desfire_clear_record_file(FreefareTag tag, uint8_t file_no);
int mifare_desfire_commit_transaction(FreefareTag tag);
int mifare_desfire_abort_transaction(FreefareTag tag);

typedef enum mifare_key_type {
MIFARE_KEY_DES,
MIFARE_KEY_2K3DES,
MIFARE_KEY_3K3DES,
MIFARE_KEY_AES128,

MIFARE_KEY_LAST = MIFARE_KEY_AES128
} MifareKeyType;

MifareDESFireKey mifare_desfire_des_key_new(const uint8_t value[8]);
MifareDESFireKey mifare_desfire_3des_key_new(const uint8_t value[16]);
MifareDESFireKey mifare_desfire_des_key_new_with_version(const uint8_t value[8]);
Expand All @@ -521,22 +530,14 @@ MifareDESFireKey mifare_desfire_aes_key_new(const uint8_t value[16]);
MifareDESFireKey mifare_desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version);
uint8_t mifare_desfire_key_get_version(MifareDESFireKey key);
void mifare_desfire_key_set_version(MifareDESFireKey key, uint8_t version);
MifareKeyType mifare_desfire_key_get_type(MifareDESFireKey key);
void mifare_desfire_key_free(MifareDESFireKey key);

uint8_t *tlv_encode(const uint8_t type, const uint8_t *istream, uint16_t isize, size_t *osize);
uint8_t *tlv_decode(const uint8_t *istream, uint8_t *type, uint16_t *size);
size_t tlv_record_length(const uint8_t *istream, size_t *field_length_size, size_t *field_value_size);
uint8_t *tlv_append(uint8_t *a, uint8_t *b);

typedef enum mifare_key_type {
MIFARE_KEY_DES,
MIFARE_KEY_2K3DES,
MIFARE_KEY_3K3DES,
MIFARE_KEY_AES128,

MIFARE_KEY_LAST = MIFARE_KEY_AES128
} MifareKeyType;

struct mifare_key_deriver;
typedef struct mifare_key_deriver *MifareKeyDeriver;

Expand Down
6 changes: 6 additions & 0 deletions libfreefare/mifare_desfire_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ mifare_desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], Mifar
return key;
}

MifareKeyType
mifare_desfire_key_get_type(MifareDESFireKey key)
{
return key->type;
}

void
mifare_desfire_key_free(MifareDESFireKey key)
{
Expand Down