diff --git a/.gitignore b/.gitignore index e64aea5e..437295c2 100644 --- a/.gitignore +++ b/.gitignore @@ -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 @@ -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 diff --git a/examples/Makefile.am b/examples/Makefile.am index 11a18ecb..54c36e1b 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -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 \ @@ -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 diff --git a/examples/mifare-desfire-ev1-change-picc-key.c b/examples/mifare-desfire-ev1-change-picc-key.c new file mode 100644 index 00000000..35f17f5f --- /dev/null +++ b/examples/mifare-desfire-ev1-change-picc-key.c @@ -0,0 +1,252 @@ +#if defined(HAVE_CONFIG_H) + #include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include + +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); +} diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 9e4e333b..7975a828 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -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]); @@ -521,6 +530,7 @@ 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); @@ -528,15 +538,6 @@ 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; diff --git a/libfreefare/mifare_desfire_key.c b/libfreefare/mifare_desfire_key.c index 1c0b4059..6d5de1c6 100644 --- a/libfreefare/mifare_desfire_key.c +++ b/libfreefare/mifare_desfire_key.c @@ -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) {