From adbba0342b2b013c3abc76e107a3210bff5f0321 Mon Sep 17 00:00:00 2001 From: Romain Tartiere Date: Fri, 24 Dec 2010 20:41:43 +0000 Subject: [PATCH] New API function mifare_desfire_set_default_key(). --- NEWS | 5 +- examples/Makefile.am | 4 + ...mifare-desfire-ev1-configure-default-key.c | 237 ++++++++++++++++++ libfreefare/freefare.h | 1 + libfreefare/mifare_desfire.c | 37 +++ 5 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 examples/mifare-desfire-ev1-configure-default-key.c diff --git a/NEWS b/NEWS index 848d6a2..f061c34 100644 --- a/NEWS +++ b/NEWS @@ -4,8 +4,9 @@ Changes between 0.2.3 and 0.3.0 [XX xxx XXXX] mifare_desfire_authenticate_iso() and mifare_desfire_authenticate_aes(). *) Add support for 3K3DES and AES cryptographic operations. *) New functions mifare_desfire_free_mem(), - mifare_desfire_set_configuration(), mifare_desfire_get_card_uid(), for - Mifare DESFire EV1 targets manipulation. + mifare_desfire_set_configuration(), mifare_desfire_set_default_key(), + mifare_desfire_get_card_uid(), for Mifare DESFire EV1 targets + manipulation. *) Deprecate authentication information when deleting the currently selected application diff --git a/examples/Makefile.am b/examples/Makefile.am index e8b042b..a1cf91b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -6,6 +6,7 @@ AM_LDFLAGS = @LIBNFC_LIBS@ bin_PROGRAMS = mifare-classic-format \ mifare-classic-write-ndef \ mifare-desfire-access \ + mifare-desfire-ev1-configure-default-key \ mifare-desfire-ev1-configure-random-uid \ mifare-desfire-format \ mifare-desfire-info \ @@ -20,6 +21,9 @@ mifare_classic_write_ndef_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare. mifare_desfire_access_SOURCES = mifare-desfire-access.c mifare_desfire_access_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la +mifare_desfire_ev1_configure_default_key_SOURCES = mifare-desfire-ev1-configure-default-key.c +mifare_desfire_ev1_configure_default_key_LDADD = -lnfc $(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 = -lnfc $(top_builddir)/libfreefare/libfreefare.la diff --git a/examples/mifare-desfire-ev1-configure-default-key.c b/examples/mifare-desfire-ev1-configure-default-key.c new file mode 100644 index 0000000..bbb29fa --- /dev/null +++ b/examples/mifare-desfire-ev1-configure-default-key.c @@ -0,0 +1,237 @@ +/*- + * Copyright (C) 2010, Romain Tartiere. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see + * + * $Id$ + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include + +uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +uint8_t new_key_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; + +#define NEW_KEY_VERSION 0x34; + +struct { + bool interactive; +} configure_options = { + .interactive = true +}; + +void +usage(char *progname) +{ + fprintf (stderr, "usage: %s [-y]\n", progname); + fprintf (stderr, "\nOptions:\n"); + fprintf (stderr, " -y Do not ask for confirmation\n"); +} + +int +main(int argc, char *argv[]) +{ + int ch; + int error = EXIT_SUCCESS; + nfc_device_t *device = NULL; + MifareTag *tags = NULL; + + while ((ch = getopt (argc, argv, "hy")) != -1) { + switch (ch) { + case 'h': + usage(argv[0]); + exit (EXIT_SUCCESS); + break; + case 'y': + configure_options.interactive = false; + break; + default: + usage(argv[0]); + exit (EXIT_FAILURE); + } + } + argc -= optind; + argv += optind; + + nfc_device_desc_t devices[8]; + size_t device_count; + + nfc_list_devices (devices, 8, &device_count); + if (!device_count) + errx (EXIT_FAILURE, "No NFC device found."); + + for (size_t d = 0; (!error) && (d < device_count); d++) { + device = nfc_connect (&(devices[d])); + if (!device) { + warnx ("nfc_connect() failed."); + error = EXIT_FAILURE; + continue; + } + + tags = freefare_get_tags (device); + if (!tags) { + nfc_disconnect (device); + errx (EXIT_FAILURE, "Error listing Mifare DESFire tags."); + } + + for (int i = 0; (!error) && tags[i]; i++) { + if (DESFIRE != freefare_get_tag_type (tags[i])) + continue; + + char *tag_uid = freefare_get_tag_uid (tags[i]); + char buffer[BUFSIZ]; + + printf ("Found %s with UID %s. ", freefare_get_tag_friendly_name (tags[i]), tag_uid); + bool do_it = true; + int res; + + if (configure_options.interactive) { + printf ("Change default key? [yN] "); + fgets (buffer, BUFSIZ, stdin); + do_it = ((buffer[0] == 'y') || (buffer[0] == 'Y')); + } else { + printf ("\n"); + } + + if (do_it) { + + res = mifare_desfire_connect (tags[i]); + if (res < 0) { + warnx ("Can't connect to Mifare DESFire target."); + error = EXIT_FAILURE; + break; + } + + MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data); + res = mifare_desfire_authenticate (tags[i], 0, default_key); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_authenticate"); + error = EXIT_FAILURE; + break; + } + mifare_desfire_key_free (default_key); + + MifareDESFireKey new_key = mifare_desfire_des_key_new (new_key_data); + mifare_desfire_key_set_version (new_key, NEW_KEY_VERSION); + res = mifare_desfire_set_default_key (tags[i], new_key); + free (new_key); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_set_default_key"); + error = EXIT_FAILURE; + break; + } + + /* + * Perform some tests to ensure the function actually worked + * (it's hard to create a unit-test to do so). + */ + + MifareDESFireAID aid = mifare_desfire_aid_new (0x112233); + res = mifare_desfire_create_application (tags[i], aid, 0xFF, 1); + + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_create_application"); + error = EXIT_FAILURE; + break; + } + + res = mifare_desfire_select_application (tags[i], aid); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_select_application"); + error = EXIT_FAILURE; + break; + } + + uint8_t version; + res = mifare_desfire_get_key_version (tags[i], 0, &version); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_get_key_version"); + error = EXIT_FAILURE; + break; + } + + if (version != NEW_KEY_VERSION) { + fprintf (stderr, "Wrong key version: %02x (expected %02x).\n"); + error = EXIT_FAILURE; + /* continue */ + } + + new_key = mifare_desfire_des_key_new (new_key_data); + res = mifare_desfire_authenticate (tags[i], 0, new_key); + free (new_key); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_authenticate"); + error = EXIT_FAILURE; + break; + } + + free (aid); + + /* Resetdefault settings */ + + res = mifare_desfire_select_application (tags[i], NULL); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_select_application"); + error = EXIT_FAILURE; + break; + } + + default_key = mifare_desfire_des_key_new (null_key_data); + + res = mifare_desfire_authenticate (tags[i], 0, default_key); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_authenticate"); + error = EXIT_FAILURE; + break; + } + + res = mifare_desfire_set_default_key (tags[i], default_key); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_set_default_key"); + error = EXIT_FAILURE; + break; + } + + mifare_desfire_key_free (default_key); + + /* Wipeout the card */ + + res = mifare_desfire_format_picc (tags[i]); + if (res < 0) { + freefare_perror (tags[i], "mifare_desfire_format_picc"); + error = EXIT_FAILURE; + break; + } + + mifare_desfire_disconnect (tags[i]); + } + + free (tag_uid); + } + + freefare_free_tags (tags); + nfc_disconnect (device); + } + + exit (error); +} diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 882d6e5..b655035 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -319,6 +319,7 @@ int mifare_desfire_format_picc (MifareTag tag); int mifare_desfire_get_version (MifareTag tag, struct mifare_desfire_version_info *version_info); int mifare_desfire_free_mem (MifareTag tag, uint32_t *size); int mifare_desfire_set_configuration (MifareTag tag, bool disable_format, bool enable_random_uid); +int mifare_desfire_set_default_key (MifareTag tag, MifareDESFireKey key); int mifare_desfire_get_card_uid (MifareTag tag, char **uid); int mifare_desfire_get_file_ids (MifareTag tag, uint8_t *files[], size_t *count); int mifare_desfire_get_file_settings (MifareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings); diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index 66b424d..121e072 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -892,6 +892,43 @@ mifare_desfire_set_configuration (MifareTag tag, bool disable_format, bool enabl return 0; } +int +mifare_desfire_set_default_key (MifareTag tag, MifareDESFireKey key) +{ + ASSERT_ACTIVE (tag); + ASSERT_MIFARE_DESFIRE (tag); + + BUFFER_INIT (cmd, 34); + BUFFER_INIT (res, 1 + CMAC_LENGTH); + + BUFFER_APPEND (cmd, 0x5C); + BUFFER_APPEND (cmd, 0x01); + size_t key_data_length; + switch (key->type) { + case T_DES: + case T_3DES: + case T_AES: + key_data_length = 16; + break; + case T_3K3DES: + key_data_length = 24; + break; + } + BUFFER_APPEND_BYTES (cmd, key->data, key_data_length); + while (__cmd_n < 26) + BUFFER_APPEND (cmd, 0x00); + BUFFER_APPEND (cmd, mifare_desfire_key_get_version (key)); + + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | ENC_COMMAND); + + DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + + ssize_t sn = __res_n; + p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); + + return 0; +} + int mifare_desfire_get_card_uid (MifareTag tag, char **uid) {