Merge the freefare-desfire branch into trunk.

This commit is contained in:
Romain Tartiere 2010-07-26 21:48:18 +00:00
parent 3f6a142b57
commit 5779d6f945
38 changed files with 4943 additions and 116 deletions

View file

@ -1,2 +1,3 @@
rconty@il4p.fr:Romuald Conty <rconty@il4p.fr>
romain.tartiere:Romain Tartière <romain@blogreen.org>
rtartiere@il4p.fr:Romain Tartière <rtartiere@il4p.fr>

View file

@ -40,7 +40,7 @@ infrastructure ready for hacking the new card support:
- Edit libfreefare/freefare.3:
- Add your tag to the `mifare_tag_type' enum documentation;
- Edit libfreefare/freefare_internal.h:
- Add a new <tag>_tag struct. It's very first member shall be `struct
- Add a new <tag>_tag struct. It's very first member SHALL be `struct
mifare_tag __tag';
- Add a <tag>_tag_new() and a <tag>_tag_free() function prototype;
- Add a ASSERT_<TAG>() macro to check the tag's type;
@ -52,9 +52,12 @@ infrastructure ready for hacking the new card support:
- Edit the freefare_free_tags() function so that it calls
<tag>_tag_free() to free your tags;
- Create libfreefare/<tag>.c and implement all that's missing:
- <tag>_tag_new() SHALL allocate all data-structure the tag may need to
- <tag>_tag_new() MUST allocate all data-structure the tag may need to
use during it's lifetime. We do not want to have any function to fail
later because the running system is out of resources;
later because the running system is out of resources. Buffers for
cryptographic operations on random amount of data MAY however be
(re)allocated on demand, in such case refrain from shrinking
unnecessarily the buffer size.
- <tag>_connect() SHOULD initialise data allocated by <tag>_tag_new().
Keep in mind that a single tag may be disconnected from and connected
to again, without being freed in the meantime. Since all memory

View file

@ -20,3 +20,8 @@ dist-hook:
fi
EXTRA_DIST = HACKING
CLEANFILES = coverage.info
clean-local: clean-local-coverage
.PHONY: clean-local-coverage
clean-local-coverage:
-rm -rf coverage

1
README
View file

@ -4,6 +4,7 @@ manipulations.
Supported tags:
- Mifare Classic 1k
- Mifare Classic 4k
- Mifare DESFire 4K
- Mifare Ultralight
Supported features:

View file

@ -18,17 +18,19 @@ AC_C_INLINE
AC_HEADER_STDBOOL
AC_TYPE_INT16_T
AC_TYPE_INT32_T
AC_TYPE_OFF_T
AC_TYPE_UINT8_T
AC_TYPE_UINT16_T
AC_TYPE_UINT32_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_HEADERS([sys/types.h])
AC_CHECK_FUNCS([memset letoh32 htole32])
AC_CHECK_FUNCS([memset letoh32 htole32 pow strerror])
AC_CHECK_HEADERS([endian.h sys/endian.h])
if test $ac_cv_header_endian_h = "no" -a $ac_cv_header_sys_endian_h = "no"; then
@ -42,6 +44,10 @@ AC_DEFINE([_BSD_SOURCE], [1], [Define on BSD to activate all library features])
CFLAGS="$CFLAGS -std=c99"
# Crypto functions for MIFARE DesFire support are provided by OpenSSL.
AC_CHECK_LIB([ssl], [DES_ecb_encrypt], [], [AC_MSG_ERROR([Cannot find libssl.])])
AC_CHECK_HEADER([openssl/des.h], [], [AC_MSG_ERROR([Cannot find libssl headers.])])
# Checks for pkg-config modules.
LIBNFC_REQUIRED_VERSION=1.3.4
PKG_CHECK_MODULES([LIBNFC], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
@ -62,5 +68,9 @@ if test x$ac_cv_enable_coverage = xyes; then
CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage"
fi
AC_OUTPUT([Makefile examples/Makefile libfreefare/Makefile libfreefare.pc test/Makefile])
AC_OUTPUT([Makefile
examples/Makefile
libfreefare/Makefile
libfreefare.pc
test/Makefile])

View file

@ -2,10 +2,24 @@ AM_CFLAGS = -I. -I$(top_srcdir)/libfreefare @LIBNFC_CFLAGS@
AM_LDFLAGS = @LIBNFC_LIBS@
bin_PROGRAMS = mifare-classic-format \
mifare-classic-write-ndef
mifare-classic-write-ndef \
mifare-desfire-access \
mifare-desfire-format \
mifare-desfire-info
mifare_classic_format_SOURCES = mifare-classic-format.c
mifare_classic_format_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la
mifare_classic_format_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la -lssl
mifare_classic_write_ndef_SOURCES = mifare-classic-write-ndef.c
mifare_classic_write_ndef_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la
mifare_desfire_access_SOURCES = mifare-desfire-access.c
mifare_desfire_access_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la -lssl
mifare_desfire_format_SOURCES = mifare-desfire-format.c
mifare_desfire_format_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la -lssl
mifare_desfire_info_SOURCES = mifare-desfire-info.c
mifare_desfire_info_LDADD = -lnfc $(top_builddir)/libfreefare/libfreefare.la -lssl -lm
CLEANFILES= *.gcno

View file

@ -138,11 +138,10 @@ int
main(int argc, char *argv[])
{
int ch;
int error = 0;
int error = EXIT_SUCCESS;
nfc_device_t *device = NULL;
MifareTag *tags = NULL;
(void)argc, (void)argv;
while ((ch = getopt (argc, argv, "fhy")) != -1) {
switch (ch) {
case 'f':
@ -163,14 +162,25 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
device = nfc_connect (NULL);
if (!device)
errx (EXIT_FAILURE, "No NFC device found.");
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; 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 classic tag.");
errx (EXIT_FAILURE, "Error listing Mifare Classic tag.");
}
for (int i = 0; (!error) && tags[i]; i++) {
@ -233,6 +243,7 @@ main(int argc, char *argv[])
freefare_free_tags (tags);
nfc_disconnect (device);
}
exit (error);
}

View file

@ -21,6 +21,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <nfc/nfc.h>
@ -124,9 +125,25 @@ main(int argc, char *argv[])
(void)argc;
(void)argv;
device = nfc_connect (NULL);
if (!device)
errx (EXIT_FAILURE, "No NFC device found.");
struct mifare_classic_key_and_type *card_write_keys;
if (!(card_write_keys = malloc (40 * sizeof (*card_write_keys)))) {
err (EXIT_FAILURE, "malloc");
}
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; 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) {
@ -134,11 +151,6 @@ main(int argc, char *argv[])
errx (EXIT_FAILURE, "Error listing MIFARE classic tag.");
}
struct mifare_classic_key_and_type *card_write_keys;
if (!(card_write_keys = malloc (40 * sizeof (*card_write_keys)))) {
err (EXIT_FAILURE, "malloc");
}
for (int i = 0; (!error) && tags[i]; i++) {
switch (freefare_get_tag_type (tags[i])) {
case CLASSIC_1K:
@ -290,6 +302,7 @@ error:
freefare_free_tags (tags);
nfc_disconnect (device);
}
free (card_write_keys);

View file

@ -0,0 +1,139 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <err.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <nfc/nfc.h>
#include <freefare.h>
uint8_t key_data_null[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int
main(int argc, char *argv[])
{
int error = EXIT_SUCCESS;
nfc_device_t *device = NULL;
MifareTag *tags = NULL;
if (argc > 1)
errx (EXIT_FAILURE, "usage: %s", argv[0]);
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; 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 tags.");
}
for (int i = 0; (!error) && tags[i]; i++) {
switch (freefare_get_tag_type (tags[i])) {
case DESFIRE_4K:
break;
default:
continue;
}
int res;
char *tag_uid = freefare_get_tag_uid (tags[i]);
res = mifare_desfire_connect (tags[i]);
if (res < 0) {
warnx ("Can't connect to Mifare DESFire target.");
error = EXIT_FAILURE;
break;
}
MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tags[i], 0, key);
if (res < 0)
errx (EXIT_FAILURE, "Authentication on master application failed");
MifareDESFireAID aid = mifare_desfire_aid_new (0x12, 0x34, 0x5);
res = mifare_desfire_create_application (tags[i], aid, 0xFF, 0x1);
if (res < 0)
errx (EXIT_FAILURE, "Application creation failed");
res = mifare_desfire_select_application (tags[i], aid);
if (res < 0)
errx (EXIT_FAILURE, "Application selection failed");
res = mifare_desfire_authenticate (tags[i], 0, key);
if (res < 0)
errx (EXIT_FAILURE, "Authentication on application failed");
res = mifare_desfire_create_std_data_file (tags[i], 1, MDCM_FULLDES, 0x0000, 20);
if (res < 0)
errx (EXIT_FAILURE, "File creation failed");
char *s= "Hello World";
res = mifare_desfire_write_data (tags[i], 1, 0, strlen (s), s);
if (res < 0)
errx (EXIT_FAILURE, "File write failed");
char buffer[20];
res = mifare_desfire_read_data (tags[i], 1, 0, 0, buffer);
if (res < 0)
errx (EXIT_FAILURE, "File read failed");
res = mifare_desfire_select_application (tags[i], NULL);
if (res < 0)
errx (EXIT_FAILURE, "Master application selection failed");
res = mifare_desfire_authenticate (tags[i], 0, key);
if (res < 0)
errx (EXIT_FAILURE, "Authentication on master application failed");
res = mifare_desfire_format_picc (tags[i]);
if (res < 0)
errx (EXIT_FAILURE, "PICC format failed");
mifare_desfire_key_free (key);
free (tag_uid);
free (aid);
mifare_desfire_disconnect (tags[i]);
}
freefare_free_tags (tags);
nfc_disconnect (device);
}
exit (error);
} /* main() */

View file

@ -0,0 +1,152 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include "config.h"
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nfc/nfc.h>
#include <freefare.h>
uint8_t null_key_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct {
bool interactive;
} format_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 (dangerous)\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':
format_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; 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++) {
switch (freefare_get_tag_type (tags[i])) {
case DESFIRE_4K:
break;
default:
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 format = true;
if (format_options.interactive) {
printf ("Format [yN] ");
fgets (buffer, BUFSIZ, stdin);
format = ((buffer[0] == 'y') || (buffer[0] == 'Y'));
} else {
printf ("\n");
}
if (format) {
int res;
MifareDESFireKey default_key = mifare_desfire_des_key_new_with_version (null_key_data);
res = mifare_desfire_connect (tags[i]);
if (res < 0) {
warnx ("Can't connect to Mifare DESFire target.");
error = EXIT_FAILURE;
break;
}
res = mifare_desfire_authenticate (tags[i], 0, default_key);
if (res < 0) {
warnx ("Can't authenticate on Mifare DESFire target.");
error = EXIT_FAILURE;
break;
}
res = mifare_desfire_format_picc (tags[i]);
if (res < 0) {
warn ("Can't format PICC.");
error = EXIT_FAILURE;
break;
}
mifare_desfire_disconnect (tags[i]);
}
free (tag_uid);
}
freefare_free_tags (tags);
nfc_disconnect (device);
}
exit (error);
} /* main() */

View file

@ -0,0 +1,118 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <err.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <nfc/nfc.h>
#include <freefare.h>
int
main(int argc, char *argv[])
{
int error = EXIT_SUCCESS;
nfc_device_t *device = NULL;
MifareTag *tags = NULL;
if (argc > 1)
errx (EXIT_FAILURE, "usage: %s", argv[0]);
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; 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 tags.");
}
for (int i = 0; (!error) && tags[i]; i++) {
switch (freefare_get_tag_type (tags[i])) {
case DESFIRE_4K:
break;
default:
continue;
}
int res;
char *tag_uid = freefare_get_tag_uid (tags[i]);
struct mifare_desfire_version_info info;
res = mifare_desfire_connect (tags[i]);
if (res < 0) {
warnx ("Can't connect to Mifare DESFire target.");
error = 1;
break;
}
res = mifare_desfire_get_version (tags[i], &info);
if (res < 0) {
warnx ("Can't get Mifare DESFire version information.");
error = 1;
break;
}
printf ("===> Version information for tag %s:\n", tag_uid);
printf ("UID: 0x%02x%02x%02x%02x%02x%02x%02x\n", info.uid[0], info.uid[1], info.uid[2], info.uid[3], info.uid[4], info.uid[5], info.uid[6]);
printf ("Batch number: 0x%02x%02x%02x%02x%02x\n", info.batch_number[0], info.batch_number[1], info.batch_number[2], info.batch_number[3], info.batch_number[4]);
printf ("Production date: week %x, 20%02x\n", info.production_week, info.production_year);
printf ("Hardware Information:\n");
printf (" Vendor ID: 0x%02x\n", info.hardware.vendor_id);
printf (" Type: 0x%02x\n", info.hardware.type);
printf (" Subtype: 0x%02x\n", info.hardware.subtype);
printf (" Version: %d.%d\n", info.hardware.version_major, info.hardware.version_minor);
printf (" Storage size: 0x%02x (%s%d bytes)\n", info.hardware.storage_size, (info.hardware.storage_size & 1) ? ">" : "=", (int)pow (2, info.hardware.storage_size >> 1));
printf (" Protocol: 0x%02x\n", info.hardware.protocol);
printf ("Software Information:\n");
printf (" Vendor ID: 0x%02x\n", info.software.vendor_id);
printf (" Type: 0x%02x\n", info.software.type);
printf (" Subtype: 0x%02x\n", info.software.subtype);
printf (" Version: %d.%d\n", info.software.version_major, info.software.version_minor);
printf (" Storage size: 0x%02x (%s%d bytes)\n", info.software.storage_size, (info.software.storage_size & 1) ? ">" : "=", (int)pow (2, info.software.storage_size >> 1));
printf (" Protocol: 0x%02x\n", info.software.protocol);
free (tag_uid);
mifare_desfire_disconnect (tags[i]);
}
freefare_free_tags (tags);
nfc_disconnect (device);
}
exit (error);
} /* main() */

View file

@ -1,69 +1,133 @@
AM_CFLAGS = -I. @LIBNFC_CFLAGS@
AM_CFLAGS = @LIBNFC_CFLAGS@
AM_LDFLAGS = @LIBNFC_LIBS@
lib_LTLIBRARIES = libfreefare.la
# TODO: Remove hexdump.c
# XXX: Remove hexdump.c on systems with a hexdump(1) function in libutil.
libfreefare_la_SOURCES = freefare.c \
hexdump.c \
mifare_classic.c \
mifare_ultralight.c \
mifare_desfire.c \
mifare_desfire_aid.c \
mifare_desfire_authenticate.c \
mifare_desfire_key.c \
mad.c \
desfire_error.c \
mifare_application.c \
tlv.c
# TODO: Remove this
# XXX: Uncomment on FreeBSD to link with libutil which provides hexdump(1).
# libfreefare_la_LIBADD = -lutil
libfreefare_la_HEADERS = freefare.h
libfreefare_ladir = $(includedir)
man_MANS = freefare.3 \
mifare_ultralight.3 \
mifare_classic.3 \
mad.3 \
mifare_application.3 \
mifare_classic.3 \
mifare_desfire.3 \
mifare_desfire_key.3 \
mifare_ultralight.3 \
tlv.3
linkedman = \
freefare.3 freefare_get_tags.3 \
freefare.3 freefare_free_tags.3 \
freefare.3 freefare_get_tag_friendly_name.3 \
freefare.3 freefare_get_tag_type.3 \
freefare.3 freefare_get_tag_uid.3 \
freefare.3 freefare_get_tag_friendly_name.3 \
freefare.3 freefare_free_tags.3 \
mifare_ultralight.3 mifare_ultralight_connect.3 \
mifare_ultralight.3 mifare_ultralight_disconnect.3 \
mifare_ultralight.3 mifare_ultralight_read.3 \
mifare_ultralight.3 mifare_ultralight_write.3 \
mifare_ultralight.3 mifare_ultralight_get_uid.3 \
mifare_classic.3 mifare_classic_connect.3 \
mifare_classic.3 mifare_classic_disconnect.3 \
mifare_classic.3 mifare_classic_authenticate.3 \
mifare_classic.3 mifare_classic_read.3 \
mifare_classic.3 mifare_classic_init_value.3 \
mifare_classic.3 mifare_classic_read_value.3 \
mifare_classic.3 mifare_classic_write.3 \
mifare_classic.3 mifare_classic_increment.3 \
mifare_classic.3 mifare_classic_decrement.3 \
mifare_classic.3 mifare_classic_restore.3 \
mifare_classic.3 mifare_classic_transfer.3 \
mifare_classic.3 mifare_classic_get_trailer_block_permission.3 \
mifare_classic.3 mifare_classic_get_data_block_permission.3 \
mifare_classic.3 mifare_classic_format_sector.3 \
mifare_classic.3 mifare_classic_get_uid.3 \
mifare_classic.3 mifare_classic_trailer_block.3 \
mad.3 mad_new.3 \
mad.3 mad_read.3 \
mad.3 mad_write.3 \
mad.3 mad_get_version.3 \
mad.3 mad_set_version.3 \
mad.3 mad_get_card_publisher_sector.3 \
mad.3 mad_set_card_publisher_sector.3 \
mad.3 mad_get_aid.3 \
mad.3 mad_set_aid.3 \
mad.3 mad_free.3 \
freefare.3 freefare_get_tags.3 \
mad.3 mad_application_read.3 \
mad.3 mad_application_write.3 \
mad.3 mad_free.3 \
mad.3 mad_get_aid.3 \
mad.3 mad_get_card_publisher_sector.3 \
mad.3 mad_get_version.3 \
mad.3 mad_new.3 \
mad.3 mad_read.3 \
mad.3 mad_set_aid.3 \
mad.3 mad_set_card_publisher_sector.3 \
mad.3 mad_set_version.3 \
mad.3 mad_write.3 \
mifare_application.3 mifare_application_alloc.3 \
mifare_application.3 mifare_application_free.3 \
mifare_application.3 mifare_application_find.3 \
tlv.3 tlv_encode.3 \
tlv.3 tlv_decode.3
mifare_application.3 mifare_application_free.3 \
mifare_classic.3 mifare_classic_authenticate.3 \
mifare_classic.3 mifare_classic_connect.3 \
mifare_classic.3 mifare_classic_decrement.3 \
mifare_classic.3 mifare_classic_disconnect.3 \
mifare_classic.3 mifare_classic_format_sector.3 \
mifare_classic.3 mifare_classic_get_data_block_permission.3 \
mifare_classic.3 mifare_classic_get_trailer_block_permission.3 \
mifare_classic.3 mifare_classic_get_uid.3 \
mifare_classic.3 mifare_classic_increment.3 \
mifare_classic.3 mifare_classic_init_value.3 \
mifare_classic.3 mifare_classic_read.3 \
mifare_classic.3 mifare_classic_read_value.3 \
mifare_classic.3 mifare_classic_restore.3 \
mifare_classic.3 mifare_classic_trailer_block.3 \
mifare_classic.3 mifare_classic_transfer.3 \
mifare_classic.3 mifare_classic_write.3 \
mifare_desfire.3 mifare_desfire_abort_transaction.3 \
mifare_desfire.3 mifare_desfire_authenticate.3 \
mifare_desfire.3 mifare_desfire_change_file_settings.3 \
mifare_desfire.3 mifare_desfire_change_key.3 \
mifare_desfire.3 mifare_desfire_change_key_settings.3 \
mifare_desfire.3 mifare_desfire_clear_record_file.3 \
mifare_desfire.3 mifare_desfire_commit_transaction.3 \
mifare_desfire.3 mifare_desfire_connect.3 \
mifare_desfire.3 mifare_desfire_create_application.3 \
mifare_desfire.3 mifare_desfire_create_backup_data_file.3 \
mifare_desfire.3 mifare_desfire_create_cyclic_record_file.3 \
mifare_desfire.3 mifare_desfire_create_linear_record_file.3 \
mifare_desfire.3 mifare_desfire_create_std_data_file.3 \
mifare_desfire.3 mifare_desfire_create_value_file.3 \
mifare_desfire.3 mifare_desfire_credit.3 \
mifare_desfire.3 mifare_desfire_credit_ex.3 \
mifare_desfire.3 mifare_desfire_debit.3 \
mifare_desfire.3 mifare_desfire_debit_ex.3 \
mifare_desfire.3 mifare_desfire_delete_application.3 \
mifare_desfire.3 mifare_desfire_delete_file.3 \
mifare_desfire.3 mifare_desfire_disconnect.3 \
mifare_desfire.3 mifare_desfire_format_picc.3 \
mifare_desfire.3 mifare_desfire_free_application_ids.3 \
mifare_desfire.3 mifare_desfire_get_application_ids.3 \
mifare_desfire.3 mifare_desfire_get_file_ids.3 \
mifare_desfire.3 mifare_desfire_get_file_settings.3 \
mifare_desfire.3 mifare_desfire_get_key_settings.3 \
mifare_desfire.3 mifare_desfire_get_key_version.3 \
mifare_desfire.3 mifare_desfire_get_value.3 \
mifare_desfire.3 mifare_desfire_get_value_ex.3 \
mifare_desfire.3 mifare_desfire_get_version.3 \
mifare_desfire.3 mifare_desfire_limited_credit.3 \
mifare_desfire.3 mifare_desfire_limited_credit_ex.3 \
mifare_desfire.3 mifare_desfire_read_data.3 \
mifare_desfire.3 mifare_desfire_read_data_ex.3 \
mifare_desfire.3 mifare_desfire_read_records.3 \
mifare_desfire.3 mifare_desfire_read_records_ex.3 \
mifare_desfire.3 mifare_desfire_select_application.3 \
mifare_desfire.3 mifare_desfire_write_data.3 \
mifare_desfire.3 mifare_desfire_write_data_ex.3 \
mifare_desfire.3 mifare_desfire_write_record.3 \
mifare_desfire.3 mifare_desfire_write_record_ex.3 \
mifare_desfire_key.3 mifare_desfire_3des_key_new.3 \
mifare_desfire_key.3 mifare_desfire_3des_key_new_with_version.3 \
mifare_desfire_key.3 mifare_desfire_des_key_new.3 \
mifare_desfire_key.3 mifare_desfire_des_key_new_with_version.3 \
mifare_desfire_key.3 mifare_desfire_key_free.3 \
mifare_desfire_key.3 mifare_desfire_key_get_version.3 \
mifare_desfire_key.3 mifare_desfire_key_set_version.3 \
mifare_ultralight.3 mifare_ultralight_connect.3 \
mifare_ultralight.3 mifare_ultralight_disconnect.3 \
mifare_ultralight.3 mifare_ultralight_get_uid.3 \
mifare_ultralight.3 mifare_ultralight_read.3 \
mifare_ultralight.3 mifare_ultralight_write.3 \
tlv.3 tlv_decode.3 \
tlv.3 tlv_encode.3
install-data-hook:
(cd $(DESTDIR)$(man3dir); for i in `echo $(linkedman) | xargs -n2 echo | awk '{print $$2}'`; do rm -f $$i; done; echo $(linkedman) | xargs -n2 $(LN_S))
@ -72,3 +136,4 @@ uninstall-hook:
(cd $(DESTDIR)$(man3dir); for i in `echo $(linkedman) | xargs -n2 echo | awk '{print $$2}'`; do rm -f $$i; done;)
EXTRA_DIST = freefare_internal.h $(man_MANS)
CLEANFILES = *.gcno

View file

@ -0,0 +1,69 @@
/*-
* Copyright (C) 2010, Romain Tartiere, Romuald Conty.
*
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <sys/types.h>
#include <stdlib.h>
#include <freefare.h>
#define EM(e) { e, #e }
static struct error_message {
uint8_t code;
char *message;
} error_messages[] = {
EM(OPERATION_OK),
EM(NO_CHANGES),
EM(OUT_OF_EEPROM_ERROR),
EM(ILLEGAL_COMMAND_CODE),
EM(INTEGRITY_ERROR),
EM(NO_SUCH_KEY),
EM(LENGTH_ERROR),
EM(PERMISSION_ERROR),
EM(PARAMETER_ERROR),
EM(APPLICATION_NOT_FOUND),
EM(APPL_INTEGRITY_ERROR),
EM(AUTHENTICATION_ERROR),
EM(ADDITIONAL_FRAME),
EM(BOUNDARY_ERROR),
EM(PICC_INTEGRITY_ERROR),
EM(COMMAND_ABORTED),
EM(PICC_DISABLED_ERROR),
EM(COUNT_ERROR),
EM(DUPLICATE_ERROR),
EM(EEPROM_ERROR),
EM(FILE_NOT_FOUND),
EM(FILE_INTEGRITY_ERROR),
{ 0, NULL }
};
const char *
desfire_error_lookup (uint8_t code)
{
struct error_message *e = error_messages;
while (e->message) {
if (e->code == code)
return (e->message);
e++;
}
return "Invalid error code";
}

View file

@ -1,4 +1,4 @@
/*
/*-
* Copyright (C) 2010, Romain Tartiere, Romuald Conty.
*
* This program is free software: you can redistribute it and/or modify it
@ -24,10 +24,11 @@
#include "freefare_internal.h"
struct supported_tag supported_tags[] = {
{ { 0x00, 0x44 }, 0x00, ULTRALIGHT, "Mifare UltraLight" },
{ { 0x00, 0x04 }, 0x08, CLASSIC_1K, "Mifare Classic 1k" },
{ { 0x00, 0x02 }, 0x18, CLASSIC_4K, "Mifare Classic 4k" },
{ { 0x00, 0x02 }, 0x38, CLASSIC_4K, "Mifare Classic 4k (Emulated)" },
{ { 0x03, 0x44 }, 0x20, DESFIRE_4K, "Mifare DESFire 4k" },
{ { 0x00, 0x44 }, 0x00, ULTRALIGHT, "Mifare UltraLight" },
};
@ -106,6 +107,9 @@ freefare_get_tags (nfc_device_t *device)
case CLASSIC_4K:
tags[tag_count-1] = mifare_classic_tag_new ();
break;
case DESFIRE_4K:
tags[tag_count-1] = mifare_desfire_tag_new ();
break;
case ULTRALIGHT:
tags[tag_count-1] = mifare_ultralight_tag_new ();
break;
@ -172,6 +176,9 @@ freefare_free_tag (MifareTag tag)
case CLASSIC_4K:
mifare_classic_tag_free (tag);
break;
case DESFIRE_4K:
mifare_desfire_tag_free (tag);
break;
case ULTRALIGHT:
mifare_ultralight_tag_free (tag);
break;

View file

@ -1,5 +1,5 @@
/*-
* Copyright (C) 2009, Romain Tartiere, Romuald Conty.
* Copyright (C) 2009, 2010, Romain Tartiere, Romuald Conty.
*
* 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
@ -41,7 +41,7 @@ enum mifare_tag_type {
// PLUS_X2K,
// PLUS_X4K,
// DESFIRE_2K,
// DESFIRE_4K,
DESFIRE_4K,
// DESFIRE_8K
};
@ -152,6 +152,191 @@ void mifare_application_free (Mad mad, const MadAid aid);
MifareClassicSectorNumber *mifare_application_find (Mad mad, const MadAid aid);
/* File types */
enum mifare_desfire_file_types {
MDFT_STANDARD_DATA_FILE = 0x00,
MDFT_BACKUP_DATA_FILE = 0x01,
MDFT_VALUE_FILE_WITH_BACKUP = 0x02,
MDFT_LINEAR_RECORD_FILE_WITH_BACKUP = 0x03,
MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP = 0x04
};
/* Communication mode */
#define MDCM_PLAIN 0x00
#define MDCM_MACING 0x01
#define MDCM_FULLDES 0x03
/* Access right */
#define MDAR(read,write,read_write,change_access_rights) ( \
(read << 12) | \
(write << 8) | \
(read_write << 4) | \
(change_access_rights) \
)
#define MDAR_READ(ar) (((ar) >> 12) & 0x0f)
#define MDAR_WRITE(ar) (((ar) >> 8) & 0x0f)
#define MDAR_READ_WRITE(ar) (((ar) >> 4) & 0x0f)
#define MDAR_CHANGE_AR(ar) ((ar) & 0x0f)
#define MDAD_KEY0 0x0
#define MDAD_KEY1 0x1
#define MDAD_KEY2 0x2
#define MDAD_KEY3 0x3
#define MDAD_KEY4 0x4
#define MDAD_KEY5 0x5
#define MDAD_KEY6 0x6
#define MDAD_KEY7 0x7
#define MDAD_KEY8 0x8
#define MDAD_KEY9 0x9
#define MDAD_KEY10 0xa
#define MDAD_KEY11 0xb
#define MDAD_KEY12 0xc
#define MDAD_KEY13 0xd
#define MDAR_FREE 0xE
#define MDAR_DENY 0xF
/* Status and error codes */
#define OPERATION_OK 0x00
#define NO_CHANGES 0x0C
#define OUT_OF_EEPROM_ERROR 0x0E
#define ILLEGAL_COMMAND_CODE 0x1C
#define INTEGRITY_ERROR 0x1E
#define NO_SUCH_KEY 0x40
#define LENGTH_ERROR 0x7E
#define PERMISSION_ERROR 0x9D
#define PARAMETER_ERROR 0x9E
#define APPLICATION_NOT_FOUND 0xA0
#define APPL_INTEGRITY_ERROR 0xA1
#define AUTHENTICATION_ERROR 0xAE
#define ADDITIONAL_FRAME 0xAF
#define BOUNDARY_ERROR 0xBE
#define PICC_INTEGRITY_ERROR 0xC1
#define COMMAND_ABORTED 0xCA
#define PICC_DISABLED_ERROR 0xCD
#define COUNT_ERROR 0xCE
#define DUPLICATE_ERROR 0xDE
#define EEPROM_ERROR 0xEE
#define FILE_NOT_FOUND 0xF0
#define FILE_INTEGRITY_ERROR 0xF1
struct mifare_desfire_aid;
typedef struct mifare_desfire_aid *MifareDESFireAID;
MifareDESFireAID mifare_desfire_aid_new (uint8_t application_code, uint8_t function_cluster_code, uint8_t n);
MifareDESFireAID mifare_desfire_aid_new_with_mad_aid (MadAid mad_aid, uint8_t n);
struct mifare_desfire_key;
typedef struct mifare_desfire_key *MifareDESFireKey;
#pragma pack (push)
#pragma pack (1)
struct mifare_desfire_version_info {
struct {
uint8_t vendor_id;
uint8_t type;
uint8_t subtype;
uint8_t version_major;
uint8_t version_minor;
uint8_t storage_size;
uint8_t protocol;
} hardware;
struct {
uint8_t vendor_id;
uint8_t type;
uint8_t subtype;
uint8_t version_major;
uint8_t version_minor;
uint8_t storage_size;
uint8_t protocol;
} software;
uint8_t uid[7];
uint8_t batch_number[5];
uint8_t production_week;
uint8_t production_year;
};
#pragma pack (pop)
struct mifare_desfire_file_settings {
uint8_t file_type;
uint8_t communication_settings;
uint16_t access_rights;
union {
struct {
uint32_t file_size;
} standard_file;
struct {
int32_t lower_limit;
int32_t upper_limit;
int32_t limited_credit_value;
uint8_t limited_credit_enabled;
} value_file;
struct {
uint32_t record_size;
uint32_t max_number_of_records;
uint32_t current_number_of_records;
} linear_record_file;
} settings;
};
int mifare_desfire_connect (MifareTag tag);
int mifare_desfire_disconnect (MifareTag tag);
uint8_t mifare_desfire_get_last_error (MifareTag tag);
int mifare_desfire_authenticate (MifareTag tag, uint8_t key_no, MifareDESFireKey key);
int mifare_desfire_change_key_settings (MifareTag tag, uint8_t settings);
int mifare_desfire_get_key_settings (MifareTag tag, uint8_t *settings, uint8_t *max_keys);
int mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_key, MifareDESFireKey old_key);
int mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *version);
int mifare_desfire_create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings, uint8_t key_no);
int mifare_desfire_delete_application (MifareTag tag, MifareDESFireAID aid);
int mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], size_t *count);
void mifare_desfire_free_application_ids (MifareDESFireAID aids[]);
int mifare_desfire_select_application (MifareTag tag, MifareDESFireAID aid);
int mifare_desfire_format_picc (MifareTag tag);
int mifare_desfire_get_version (MifareTag tag, struct mifare_desfire_version_info *version_info);
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);
int mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights);
int mifare_desfire_create_std_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
int mifare_desfire_create_backup_data_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t file_size);
int mifare_desfire_create_value_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, int32_t lower_limit, int32_t upper_limit, int32_t value, uint8_t limited_credit_enable);
int mifare_desfire_create_linear_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
int mifare_desfire_create_cyclic_record_file (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights, uint32_t record_size, uint32_t max_number_of_records);
int mifare_desfire_delete_file (MifareTag tag, uint8_t file_no);
ssize_t mifare_desfire_read_data (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
ssize_t mifare_desfire_read_data_ex (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
ssize_t mifare_desfire_write_data (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
ssize_t mifare_desfire_write_data_ex (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
int mifare_desfire_get_value (MifareTag tag, uint8_t file_no, int32_t *value);
int mifare_desfire_get_value_ex (MifareTag tag, uint8_t file_no, int32_t *value, int cs);
int mifare_desfire_credit (MifareTag tag, uint8_t file_no, int32_t amount);
int mifare_desfire_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs);
int mifare_desfire_debit (MifareTag tag, uint8_t file_no, int32_t amount);
int mifare_desfire_debit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs);
int mifare_desfire_limited_credit (MifareTag tag, uint8_t file_no, int32_t amount);
int mifare_desfire_limited_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs);
ssize_t mifare_desfire_write_record (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
ssize_t mifare_desfire_write_record_ex (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
ssize_t mifare_desfire_read_records (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data);
ssize_t mifare_desfire_read_records_ex (MifareTag tag, uint8_t file_no, off_t offset, size_t length, void *data, int cs);
int mifare_desfire_clear_record_file (MifareTag tag, uint8_t file_no);
int mifare_desfire_commit_transaction (MifareTag tag);
int mifare_desfire_abort_transaction (MifareTag tag);
MifareDESFireKey mifare_desfire_des_key_new (uint8_t value[8]);
MifareDESFireKey mifare_desfire_3des_key_new (uint8_t value[16]);
MifareDESFireKey mifare_desfire_des_key_new_with_version (uint8_t value[8]);
MifareDESFireKey mifare_desfire_3des_key_new_with_version (uint8_t value[16]);
uint8_t mifare_desfire_key_get_version (MifareDESFireKey key);
void mifare_desfire_key_set_version (MifareDESFireKey key, uint8_t version);
void mifare_desfire_key_free (MifareDESFireKey key);
const char *desfire_error_lookup (uint8_t error);
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);
@ -161,5 +346,4 @@ uint8_t *tlv_append (uint8_t *a, uint8_t *b);
}
#endif // __cplusplus
#endif /* !__FREEFARE_H__ */

View file

@ -1,4 +1,4 @@
/*
/*-
* Copyright (C) 2010, Romain Tartiere, Romuald Conty.
*
* This program is free software: you can redistribute it and/or modify it
@ -22,6 +22,8 @@
#include "config.h"
#include <openssl/des.h>
/*
* Endienness macros
*
@ -39,10 +41,6 @@
* dealt with).
*/
#if !defined(le32toh) && defined(letoh32)
# define le32toh(x) letoh32(x)
#endif
#if !defined(le32toh) && defined(bswap_32)
# if BYTE_ORDER == LITTLE_ENDIAN
# define be32toh(x) bswap_32(x)
@ -71,6 +69,8 @@
# endif
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
struct mad_sector_0x00;
struct mad_sector_0x10;
@ -78,11 +78,24 @@ struct mad_sector_0x10;
void nxp_crc (uint8_t *crc, const uint8_t value);
MifareTag mifare_classic_tag_new (void);
void mifare_classic_tag_free (MifareTag tag);
MifareTag mifare_desfire_tag_new (void);
void mifare_desfire_tag_free (MifareTag tags);
MifareTag mifare_ultralight_tag_new (void);
void mifare_ultralight_tag_free (MifareTag tag);
uint8_t sector_0x00_crc8 (Mad mad);
uint8_t sector_0x10_crc8 (Mad mad);
typedef enum {
MD_SEND,
MD_RECEIVE
} MifareDirection;
void *mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int communication_settings);
void *mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int communication_settings);
void mifare_cbc_des (MifareDESFireKey key, uint8_t *data, size_t data_size, MifareDirection direction, int mac);
void rol8(uint8_t *data);
void *assert_crypto_buffer_size (MifareTag tag, size_t nbytes);
#define MIFARE_ULTRALIGHT_PAGE_COUNT 16
struct supported_tag {
@ -123,6 +136,33 @@ struct mifare_classic_tag {
} cached_access_bits;
};
struct mifare_desfire_aid {
uint8_t data[3];
};
struct mifare_desfire_key {
uint8_t data[16];
enum {
T_DES,
T_3DES
} type;
DES_key_schedule ks1;
DES_key_schedule ks2;
};
struct mifare_desfire_tag {
struct mifare_tag __tag;
uint8_t last_picc_error;
char *last_pcd_error;
MifareDESFireKey session_key;
uint8_t authenticated_key_no;
uint8_t *crypto_buffer;
size_t crypto_buffer_size;
};
MifareDESFireKey mifare_desfire_session_key_new (uint8_t rnda[8], uint8_t rndb[8], MifareDESFireKey authentication_key);
struct mifare_ultralight_tag {
struct mifare_tag __tag;
@ -140,8 +180,9 @@ struct mifare_ultralight_tag {
#define ASSERT_ACTIVE(tag) do { if (!tag->active) return errno = ENXIO, -1; } while (0)
#define ASSERT_INACTIVE(tag) do { if (tag->active) return errno = ENXIO, -1; } while (0)
#define ASSERT_MIFARE_ULTRALIGHT(tag) do { if (tag->tag_info->type != ULTRALIGHT) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_CLASSIC(tag) do { if ((tag->tag_info->type != CLASSIC_1K) && (tag->tag_info->type != CLASSIC_4K)) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_DESFIRE(tag) do { if (tag->tag_info->type != DESFIRE_4K) return errno = ENODEV, -1; } while (0)
#define ASSERT_MIFARE_ULTRALIGHT(tag) do { if (tag->tag_info->type != ULTRALIGHT) return errno = ENODEV, -1; } while (0)
/*
* MifareTag cast macros
@ -150,6 +191,7 @@ struct mifare_ultralight_tag {
* MifareTag structures to concrete Tags (e.g. MIFARE Classic tag).
*/
#define MIFARE_CLASSIC(tag) ((struct mifare_classic_tag *) tag)
#define MIFARE_DESFIRE(tag) ((struct mifare_desfire_tag *) tag)
#define MIFARE_ULTRALIGHT(tag) ((struct mifare_ultralight_tag *) tag)
/*

96
libfreefare/hexdump.c Normal file
View file

@ -0,0 +1,96 @@
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* 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, this list of conditions and the following disclaimer.
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
*/
//#include <sys/cdefs.h>
//__FBSDID("$FreeBSD: stable/8/lib/libutil/hexdump.c 180161 2008-07-01 22:30:57Z jhb $");
#include <sys/types.h>
#include <libutil.h>
#include <stdio.h>
void
hexdump(const void *ptr, int length, const char *hdr, int flags)
{
int i, j, k;
int cols;
const unsigned char *cp;
char delim;
if ((flags & HD_DELIM_MASK) != 0)
delim = (flags & HD_DELIM_MASK) >> 8;
else
delim = ' ';
if ((flags & HD_COLUMN_MASK) != 0)
cols = flags & HD_COLUMN_MASK;
else
cols = 16;
cp = ptr;
for (i = 0; i < length; i+= cols) {
if (hdr != NULL)
printf("%s", hdr);
if ((flags & HD_OMIT_COUNT) == 0)
printf("%04x ", i);
if ((flags & HD_OMIT_HEX) == 0) {
for (j = 0; j < cols; j++) {
k = i + j;
if (k < length)
printf("%c%02x", delim, cp[k]);
else
printf(" ");
}
}
if ((flags & HD_OMIT_CHARS) == 0) {
printf(" |");
for (j = 0; j < cols; j++) {
k = i + j;
if (k >= length)
printf(" ");
else if (cp[k] >= ' ' && cp[k] <= '~')
printf("%c", cp[k]);
else
printf(".");
}
printf("|");
}
printf("\n");
}
}

View file

@ -32,6 +32,7 @@
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <freefare.h>
@ -46,8 +47,6 @@
#define SECTOR_0X00_AIDS 15
#define SECTOR_0X10_AIDS 23
#define MIN(a, b) ( (a < b) ? a : b )
struct mad_sector_0x00 {
uint8_t crc;
uint8_t info;
@ -83,8 +82,8 @@ mad_new (uint8_t version)
return NULL;
mad->version = version;
memset (&(mad->sector_0x00), '\0', sizeof (mad->sector_0x00));
memset (&(mad->sector_0x10), '\0', sizeof (mad->sector_0x10));
bzero (&(mad->sector_0x00), sizeof (mad->sector_0x00));
bzero (&(mad->sector_0x10), sizeof (mad->sector_0x10));
return mad;
}
@ -331,7 +330,7 @@ mad_set_version (Mad mad, const uint8_t version)
{
if ((version == 2) && (mad->version == 1)) {
/* We use a larger MAD so initialise the new blocks */
memset (&(mad->sector_0x10), '\0', sizeof (mad->sector_0x10));
bzero (&(mad->sector_0x10), sizeof (mad->sector_0x10));
}
mad->version = version;
}

View file

@ -55,6 +55,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <nfc/nfc.h>
@ -663,7 +664,7 @@ mifare_classic_format_sector (MifareTag tag, const MifareClassicSectorNumber sec
}
MifareClassicBlock empty_data_block;
memset (empty_data_block, '\x00', sizeof (empty_data_block));
bzero (empty_data_block, sizeof (empty_data_block));
MifareClassicBlock default_trailer_block = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Key A */

View file

@ -0,0 +1,525 @@
.\" 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 <http://www.gnu.org/licenses/>
.\"
.\" $Id$
.\"
.Dd July 11, 2010
.Dt MIFARE_DESFIRE 3
.Os
.\" _ _
.\" | \ | | __ _ _ __ ___ ___
.\" | \| |/ _` | '_ ` _ \ / _ \
.\" | |\ | (_| | | | | | | __/
.\" |_| \_|\__,_|_| |_| |_|\___|
.\"
.Sh NAME
.Nm mifare_desfire_connect ,
.Nm mifare_desfire_disconnect .
.\"
.Nm mifare_desfire_authenticate ,
.Nm mifare_desfire_change_key_settings ,
.Nm mifare_desfire_get_key_settings ,
.Nm mifare_desfire_change_key ,
.Nm mifare_desfire_get_key_version ,
.\"
.Nm mifare_desfire_create_application ,
.Nm mifare_desfire_delete_application ,
.Nm mifare_desfire_get_application_ids ,
.Nm mifare_desfire_free_application_ids ,
.Nm mifare_desfire_select_application ,
.\"
.Nm mifare_desfire_format_picc ,
.\"
.Nm mifare_desfire_get_version ,
.\"
.Nm mifare_desfire_get_file_ids ,
.Nm mifare_desfire_get_file_settings ,
.Nm mifare_desfire_change_file_settings ,
.Nm mifare_desfire_create_std_data_file ,
.Nm mifare_desfire_create_backup_data_file ,
.Nm mifare_desfire_create_value_file ,
.Nm mifare_desfire_create_linear_record_file ,
.Nm mifare_desfire_create_cyclic_record_file ,
.Nm mifare_desfire_delete_file ,
.\"
.Nm mifare_desfire_read_data ,
.Nm mifare_desfire_read_data_ex ,
.Nm mifare_desfire_write_data ,
.Nm mifare_desfire_write_data_ex ,
.Nm mifare_desfire_get_value ,
.Nm mifare_desfire_get_value_ex ,
.Nm mifare_desfire_credit ,
.Nm mifare_desfire_credit_ex ,
.Nm mifare_desfire_debit ,
.Nm mifare_desfire_debit_ex ,
.Nm mifare_desfire_limited_credit ,
.Nm mifare_desfire_limited_credit_ex ,
.Nm mifare_desfire_write_record ,
.Nm mifare_desfire_write_record_ex ,
.Nm mifare_desfire_read_records ,
.Nm mifare_desfire_read_records_ex ,
.Nm mifare_desfire_clear_record_file ,
.Nm mifare_desfire_commit_transaction ,
.Nm mifare_desfire_abort_transaction ,
.Nd Mifare DESFire Manipulation Functions
.\" _ _ _
.\" | | (_) |__ _ __ __ _ _ __ _ _
.\" | | | | '_ \| '__/ _` | '__| | | |
.\" | |___| | |_) | | | (_| | | | |_| |
.\" |_____|_|_.__/|_| \__,_|_| \__, |
.\" |___/
.Sh LIBRARY
Mifare card manipulation library (libfreefare, \-lfreefare)
.\" ____ _
.\" / ___| _ _ _ __ ___ _ __ ___(_)___
.\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __|
.\" ___) | |_| | | | | (_) | |_) \__ \ \__ \
.\" |____/ \__, |_| |_|\___/| .__/|___/_|___/
.\" |___/ |_|
.Sh SYNOPSIS
.In freefare.h
.Ft int
.Fn mifare_desfire_connect "MifareTag tag"
.Ft int
.Fn mifare_desfire_disconnect "MifareTag tag"
.\".Ft uint8_t
.\".Fn mifare_desfire_get_last_error "MifareTag tag"
.Ft int
.Fn mifare_desfire_authenticate "MifareTag tag" "uint8_t key_no" "MifareDESFireKey key"
.Ft int
.Fn mifare_desfire_change_key_settings "MifareTag tag" "uint8_t settings"
.Ft int
.Fn mifare_desfire_get_key_settings "MifareTag tag" "uint8_t *settings" "uint8_t *max_keys"
.Ft int
.Fn mifare_desfire_change_key "MifareTag tag" "uint8_t key_no" "MifareDESFireKey new_key" "MifareDESFireKey old_key"
.Ft int
.Fn mifare_desfire_get_key_version "MifareTag tag" "uint8_t key_no" "uint8_t *version"
.Ft int
.Fn mifare_desfire_create_application "MifareTag tag" "MifareDESFireAID aid" "uint8_t settings" "uint8_t key_no"
.Ft int
.Fn mifare_desfire_delete_application "MifareTag tag" "MifareDESFireAID aid"
.Ft int
.Fn mifare_desfire_get_application_ids "MifareTag tag" "MifareDESFireAID *aids[]" "size_t *count"
.Ft void
.Fn mifare_desfire_free_application_ids "MifareDESFireAID aids[]"
.Ft int
.Fn mifare_desfire_select_application "MifareTag tag" "MifareDESFireAID aid"
.Ft int
.Fn mifare_desfire_format_picc "MifareTag tag"
.Ft int
.Fn mifare_desfire_get_version "MifareTag tag" "struct mifare_desfire_version_info *version_info"
.Ft int
.Fn mifare_desfire_get_file_ids "MifareTag tag" "uint8_t *files[]" "size_t *count"
.Ft int
.Fn mifare_desfire_get_file_settings "MifareTag tag" "uint8_t file_no" "struct mifare_desfire_file_settings *settings"
.Ft int
.Fn mifare_desfire_change_file_settings "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights"
.Ft int
.Fn mifare_desfire_create_std_data_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size"
.Ft int
.Fn mifare_desfire_create_backup_data_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t file_size"
.Ft int
.Fn mifare_desfire_create_value_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "int32_t lower_limit" "int32_t upper_limit" "int32_t value" "uint8_t limited_credit_enable"
.Ft int
.Fn mifare_desfire_create_linear_record_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records"
.Ft int
.Fn mifare_desfire_create_cyclic_record_file "MifareTag tag" "uint8_t file_no" "uint8_t communication_settings" "uint16_t access_rights" "uint32_t record_size" "uint32_t max_number_of_records"
.Ft int
.Fn mifare_desfire_delete_file "MifareTag tag" "uint8_t file_no"
.Ft ssize_t
.Fn mifare_desfire_read_data "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data"
.Ft ssize_t
.Fn mifare_desfire_read_data_ex "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data" "int cs"
.Ft ssize_t
.Fn mifare_desfire_write_data "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data"
.Ft ssize_t
.Fn mifare_desfire_write_data_ex "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data" "int cs"
.Ft int
.Fn mifare_desfire_get_value "MifareTag tag" "uint8_t file_no" "int32_t *value"
.Ft int
.Fn mifare_desfire_get_value_ex "MifareTag tag" "uint8_t file_no" "int32_t *value" "int cs"
.Ft int
.Fn mifare_desfire_credit "MifareTag tag" "uint8_t file_no" "int32_t amount"
.Ft int
.Fn mifare_desfire_credit_ex "MifareTag tag" "uint8_t file_no" "int32_t amount" "int cs"
.Ft int
.Fn mifare_desfire_debit "MifareTag tag" "uint8_t file_no" "int32_t amount"
.Ft int
.Fn mifare_desfire_debit_ex "MifareTag tag" "uint8_t file_no" "int32_t amount" "int cs"
.Ft int
.Fn mifare_desfire_limited_credit "MifareTag tag" "uint8_t file_no" "int32_t amount"
.Ft int
.Fn mifare_desfire_limited_credit_ex "MifareTag tag" "uint8_t file_no" "int32_t amount" "int cs"
.Ft ssize_t
.Fn mifare_desfire_write_record "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data"
.Ft ssize_t
.Fn mifare_desfire_write_record_ex "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data" "int cs"
.Ft ssize_t
.Fn mifare_desfire_read_records "MifareTag tag" "uint8_t file_no" "off_t offset" "size_t length" "void *data"
.Ft ssize_t
.Fn mifare_desfire_read_records_ex "MifareTag tag" "uint7_t file_no" "off_t offset" "size_t length" "void *data" "int cs"
.Ft int
.Fn mifare_desfire_clear_record_file "MifareTag tag" "uint8_t file_no"
.Ft int
.Fn mifare_desfire_commit_transaction "MifareTag tag"
.Ft int
.Fn mifare_desfire_abort_transaction "MifareTag tag"
.\" ____ _ _ _
.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __
.\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \
.\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | |
.\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_|
.\" |_|
.Sh DESCRIPTION
The
.Fn mifare_desfire_*
functions allows management of Mifare DESFire tags.
.Pp
.Ss Card-level operations
The
.Fn mifare_desfire_connect
and
.Fn mifare_desfire_disconnect
functions activates and deactivates the provided
.Vt tag .
All
.Fn mifare_desfire_*
functions that operates on a
.Vt tag
require it to be on activated.
.Pp
After activation, the selected application is the master application. It is
possible to select another application using the
.Fn mifare_desfire_select_application
function (see bellow).
.Pp
The
.Fn mifare_desfire_get_version
function retrieve various information about the provided
.Vt tag ,
including UID, batch number, production date, and hardware and software
information. Refer to the freefare.h header file for details about the
.Vt settings
field.
.Pp
The
.Fn mifare_desfire_format_picc
function resets
.Vt tag
to factory defaults. For this function to work, a previous authentication with
the card master key is required.
.Pp
.Ss Application-level operations
The
.Fn mifare_desfire_select_application
function makes the application identified by
.Vt aid
the active one. Further file operations will be performed in the context of
this application. After a call to
.Vt mifare_desfire_connect ,
the default application is the card master application. It can be selected
again calling the
.Fn mifare_desfire_select_application
function either with an
.Vt aid
with all its fields set to 0, or by providing the NULL
.Vt aid .
.Pp
The
.Fn mifare_desfire_authenticate
function performs an authentication using the key number
.Vt key_no
on the card and the
.Vt key
(3)DES key on
.Vt tag .
.Pp
The
.Fn mifare_desfire_get_key_settings
function, returns the
.Vt settings
and the number of keys
.Vt max_keys
of the selected application.
.Pp
The
.Fn mifare_desfire_change_key_settings
function changes the selected application settings to
.Vt settings .
The application number of keys cannot be changed after the application has been
created.
.Pp
The
.Fn mifare_desfire_change_key
changes the key
.Vt key_no
from
.Vt old_key
to
.Vt new_key
on
.Vt tag .
Depending on the application settings, a previous authentication with the same
key or another key may be required.
.Pp
The
.Fn mifare_desfire_get_key_version
function retrieves the
.Vt version
of the key with number
.Vt key_no
of the selected application.
.Pp
The
.Fn mifare_desfire_create_application
function, creates an application with AID
.Vt aid ,
the
.Vt settings
key settings and
.Vt key_no
authentication keys. Authentication keys are set to 0 after creation.
.Pp
The
.Fn mifare_desfire_delete_application
deletes the application identified by AID
.Vt aid .
.Pp
The
.Fn mifare_desfire_get_application_ids
function returns a list of all applications of the card. The
.Vt aids
array has to be freed after usage calling
.Fn mifare_desfire_free_application_ids .
.Pp
.Ss File-level operations
The
.Fn mifare_desfire_get_file_ids
function returns the list of
.Vt count
files in the selected application as
.Vt files .
The memory allocated for
.Vt files
has to be reclaimed using
.Xr free 3 .
.Pp
The
.Fn mifare_desfire_get_file_settings
function retrieves the
.Vt settings
of the file
.Vt file_no
of the selected application of
.Vt tag .
.Pp
The
.Fn mifare_desfire_change_file_settings
function change the
.Vt communication_settings
and
.Vt access_rights
of the file
.Vt file_no
of the selected application of
.Vt tag .
.Pp
The
.Fn mifare_desfire_create_*
family of functions create a new file
.Vt file_no
with the provided
.Vt communication_settings
and
.Vt access_rights
on
.Vt tag.
.Bl -tag -width indent
.It Fn mifare_desfire_create_std_data_file
creates a standard data file of size
.Vt file_size .
.It Fn mifare_desfire_create_backup_data_file
creates a backup data file of size
.Vt file_size .
.It Fn mifare_desfire_create_value_file
creates a value file of value
.Vt value
constrained in the range
.Vt lower_limit
.Vt upper_limit ,
and with the
.Vt limited_credit_enable
settings.
.It Fn mifare_desfire_create_linear_record_file
creates a linear record file that can hold
.Vt max_number_of_records
records of size
.Vt record_size .
.It Fn mifare_desfire_create_cyclic_record_file
creates a cyclic record file that can hold
.Vt max_number_of_records
records of size
.Vt record_size .
.El
.Pp
The
.Fn mifare_desfire_delete_file
removes the file
.Vt file_no
from the selected application of
.Vt tag .
.Ss Data-level operations
The
.Fn mifare_desfire_read_data
function reads
.Vt length
bytes of data from offset
.Vt offset
of the file
.Vt file_no
and copies it to
.Vt data .
If
.Vt length
is set to 0, the file is read to end. The function returns the number of bytes
read.
.Pp
The
.Fn mifare_desfire_write_data
function writes
.Vt length
bytes of data from offset
.Vt offset
of the file
.Vt file_no
and copies it to
.Vt data .
The function returns the number of bytes written.
.Pp
The
.Fn mifare_desfire_get_value
reads the
.Vt value
of the file
.Vt file_no
of the selected application.
.Pp
The
.Fn mifare_desfire_credit
function adds
.Vt amount
to the value of the file
.Vt file_no
of the selected application.
.Pp
The
.Fn mifare_desfire_debit
function substracts
.Vt amount
to the value of the file
.Vt file_no
of the selected application.
.Pp
to the value of the file
.Vt file_no
of the selected application.
.Pp
The
.Fn mifare_desfire_limited_credit
function adds
.Vt amount
to the value of the file
.Vt file_no
of the selected application.
.Pp
The
.Fn mifare_desfire_write_record
function writes
.Vt length
records starting at record
.Vt offset
of
.Vt data
in the file
.Vt file_no
and returns the number of bytes written.
.Pp
The
.Fn mifare_desfire_read_records
function reads
.Vt length
records starting at record
.Vt offset
from the file
.Vt file_no
and copy them to
.Vt data ,
returning the number of bytes read.
.Pp
The
.Fn mifare_desfire_clear_record_file
function erase all records from the file
.Vt file_no
of the selected application.
.Pp
The
.Fn mifare_desfire_commit_transaction
validates the set of pending changes on the
.Vt tag ,
while the
.Fn mifare_desfire_abort_transaction
rollbacks the changes.
.Pp
All data-manipulation functions that read data from and write data to files
come with an
.Fn *_ex
variant (e.g.
.Fn mifare_desfire_read_data_ex )
which accepts an extra parameter
.Vt cs
that defines the communication settings to use. If not provided, the library
will try to read-out this value from the file's configuration. Because reading
this information may be denied, the
.Fn *_ex
variant of functions still allows using the library for advanced usage.
.\" ____ _ _
.\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___
.\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __|
.\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \
.\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/
.\"
.Sh RETURN VALUES
Unless stated otherwise, all other functions return a value greater than or
equal to
.Va 0
on success or
.Va -1
on failure.
.\" ____ _
.\" / ___| ___ ___ __ _| |___ ___
.\" \___ \ / _ \/ _ \ / _` | / __|/ _ \
.\" ___) | __/ __/ | (_| | \__ \ (_) |
.\" |____/ \___|\___| \__,_|_|___/\___/
.\"
.Sh SEE ALSO
.Xr freefare 3
.\" _ _ _
.\" / \ _ _| |_| |__ ___ _ __ ___
.\" / _ \| | | | __| '_ \ / _ \| '__/ __|
.\" / ___ \ |_| | |_| | | | (_) | | \__ \
.\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/
.\"
.Sh AUTHORS
.An Romain Tartiere Aq romain@il4p.org

1247
libfreefare/mifare_desfire.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <errno.h>
#include <stdlib.h>
#include <freefare.h>
#include "freefare_internal.h"
MifareDESFireAID
mifare_desfire_aid_new (uint8_t application_code, uint8_t function_cluster_code, uint8_t n)
{
MadAid mad_aid = { application_code, function_cluster_code };
return mifare_desfire_aid_new_with_mad_aid (mad_aid, n);
}
MifareDESFireAID
mifare_desfire_aid_new_with_mad_aid (MadAid mad_aid, uint8_t n)
{
MifareDESFireAID res;
if (n & 0xf0)
return errno = EINVAL, NULL;
if ((res = malloc (sizeof (*res)))) {
res->data[0] = 0xf0 | (mad_aid.function_cluster_code >> 4);
res->data[1] = (uint8_t) (((mad_aid.function_cluster_code & 0x0f) << 4) | ((mad_aid.application_code & 0xf0) >> 4));
res->data[2] = ((mad_aid.application_code & 0x0f) << 4) | n;
}
return res;
}

View file

@ -0,0 +1,297 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include "config.h"
#include <openssl/des.h>
#include <string.h>
#include <strings.h>
#include <freefare.h>
#include "freefare_internal.h"
static void xor8 (uint8_t *ivect, uint8_t *data);
static void mifare_des (MifareDESFireKey key, uint8_t *data, uint8_t *ivect, MifareDirection direction, int mac);
static size_t padded_data_length (size_t nbytes);
static size_t maced_data_length (size_t nbytes);
static size_t enciphered_data_length (size_t nbytes);
static void
xor8 (uint8_t *ivect, uint8_t *data)
{
for (int i = 0; i < 8; i++) {
data[i] ^= ivect[i];
}
}
void
rol8(uint8_t *data)
{
uint8_t first = data[0];
for (int i = 0; i < 7; i++) {
data[i] = data[i+1];
}
data[7] = first;
}
/*
* Size required to store nbytes of data in a buffer of size n*8.
*/
static size_t
padded_data_length (size_t nbytes)
{
if (nbytes % 8)
return ((nbytes / 8) + 1) * 8;
else
return nbytes;
}
/*
* Buffer size required to MAC nbytes of data
*/
static size_t
maced_data_length (size_t nbytes)
{
return nbytes + 4;
}
/*
* Buffer size required to encipher nbytes of data and a two bytes CRC.
*/
static size_t
enciphered_data_length (size_t nbytes)
{
return padded_data_length (nbytes + 2);
}
/*
* Ensure that tag's crypto buffer is large enough to store nbytes of data.
*/
void *
assert_crypto_buffer_size (MifareTag tag, size_t nbytes)
{
void *res = MIFARE_DESFIRE (tag)->crypto_buffer;
if (MIFARE_DESFIRE (tag)->crypto_buffer_size < nbytes) {
if ((res = realloc (MIFARE_DESFIRE (tag)->crypto_buffer, nbytes))) {
MIFARE_DESFIRE (tag)->crypto_buffer = res;
MIFARE_DESFIRE (tag)->crypto_buffer_size = nbytes;
}
}
return res;
}
void *
mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int communication_settings)
{
void *res;
uint8_t mac[4];
size_t edl, mdl;
switch (communication_settings) {
case 0:
case 2:
res = data;
break;
case 1:
edl = padded_data_length (*nbytes);
if (!(res = assert_crypto_buffer_size (tag, edl)))
abort();
// Fill in the crypto buffer with data ...
memcpy (res, data, *nbytes);
// ... and 0 padding
bzero ((uint8_t *)res + *nbytes, edl - *nbytes);
mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, res, edl, MD_SEND, 1);
memcpy (mac, (uint8_t *)res + edl - 8, 4);
mdl = maced_data_length (*nbytes);
if (!(res = assert_crypto_buffer_size (tag, mdl)))
abort();
memcpy (res, data, *nbytes);
memcpy ((uint8_t *)res + *nbytes, mac, 4);
*nbytes += 4;
break;
case 3:
edl = enciphered_data_length (*nbytes);
if (!(res = assert_crypto_buffer_size (tag, edl)))
abort();
// Fill in the crypto buffer with data ...
memcpy (res, data, *nbytes);
// ... CRC ...
append_iso14443a_crc (res, *nbytes);
// ... and 0 padding
bzero ((uint8_t *)(res) + *nbytes + 2, edl - *nbytes - 2);
*nbytes = edl;
mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, res, *nbytes, MD_SEND, 0);
break;
default:
res = NULL;
break;
}
return res;
}
void *
mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int communication_settings)
{
void *res = data;
size_t edl;
void *edata;
switch (communication_settings) {
case 0:
case 2:
break;
case 1:
*nbytes -= 4;
edl = enciphered_data_length (*nbytes);
edata = malloc (edl);
memcpy (edata, data, *nbytes);
bzero ((uint8_t *)edata + *nbytes, edl - *nbytes);
mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, edata, edl, MD_SEND, 1);
/* ,^^^^^^^
* No! This is not a typo! ---------------------------------'
*/
if (0 != memcmp ((uint8_t *)data + *nbytes, (uint8_t *)edata + edl - 8, 4)) {
printf ("MACing not verified\n");
*nbytes = -1;
res = NULL;
}
free (edata);
break;
case 3:
mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, res, *nbytes, MD_RECEIVE, 0);
/*
* Look for the CRC and ensure it is following by NULL padding. We
* can't start by the end because the CRC is supposed to be 0 when
* verified, and accumulating 0's in it should not change it.
*/
bool verified = false;
int end_crc_pos = *nbytes - 7; // The CRC can be over two blocks
do {
uint16_t crc;
iso14443a_crc (res, end_crc_pos, (uint8_t *)&crc);
if (!crc) {
verified = true;
for (int n = end_crc_pos; n < *nbytes; n++) {
uint8_t byte = ((uint8_t *)res)[n];
if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) ))
verified = false;
}
}
if (verified) {
*nbytes = end_crc_pos - 2;
} else {
end_crc_pos++;
}
} while (!verified && (end_crc_pos < *nbytes));
if (!verified) {
printf ("(3)DES not verified\n");
*nbytes = -1;
res = NULL;
}
break;
default:
printf ("Unknown communication settings\n");
*nbytes = -1;
res = NULL;
break;
}
return res;
}
static void
mifare_des (MifareDESFireKey key, uint8_t *data, uint8_t *ivect, MifareDirection direction, int mac)
{
uint8_t ovect[8];
if (direction == MD_SEND) {
xor8 (ivect, data);
} else {
memcpy (ovect, data, 8);
}
uint8_t edata[8];
switch (key->type) {
case T_DES:
if (mac) {
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
} else {
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
}
memcpy (data, edata, 8);
break;
case T_3DES:
if (mac) {
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_DECRYPT);
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_ENCRYPT);
} else {
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
DES_ecb_encrypt ((DES_cblock *) edata, (DES_cblock *) data, &(key->ks2), DES_ENCRYPT);
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
}
memcpy (data, edata, 8);
break;
}
if (direction == MD_SEND) {
memcpy (ivect, data, 8);
} else {
xor8 (ivect, data);
memcpy (ivect, ovect, 8);
}
}
void
mifare_cbc_des (MifareDESFireKey key, uint8_t *data, size_t data_size, MifareDirection direction, int mac)
{
size_t offset = 0;
uint8_t ivect[8];
bzero (ivect, sizeof (ivect));
while (offset < data_size) {
mifare_des (key, data + offset, ivect, direction, mac);
offset += 8;
}
}

View file

@ -0,0 +1,134 @@
.\" 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 <http://www.gnu.org/licenses/>
.\"
.\" $Id$
.\"
.Dd July 20, 2010
.Dt MIFARE_DESFIRE_KEY 3
.Os
.\" _ _
.\" | \ | | __ _ _ __ ___ ___
.\" | \| |/ _` | '_ ` _ \ / _ \
.\" | |\ | (_| | | | | | | __/
.\" |_| \_|\__,_|_| |_| |_|\___|
.\"
.Sh NAME
.Nm mifare_desfire_des_key_new ,
.Nm mifare_desfire_3des_key_new ,
.Nm mifare_desfire_des_key_new_with_version ,
.Nm mifare_desfire_3des_key_new_with_version ,
.Nm mifare_desfire_key_get_version ,
.Nm mifare_desfire_key_set_version ,
.Nm mifare_desfire_key_free
.Nd Mifare DESFire keys Manipulation Functions
.\" _ _ _
.\" | | (_) |__ _ __ __ _ _ __ _ _
.\" | | | | '_ \| '__/ _` | '__| | | |
.\" | |___| | |_) | | | (_| | | | |_| |
.\" |_____|_|_.__/|_| \__,_|_| \__, |
.\" |___/
.Sh LIBRARY
Mifare card manipulation library (libfreefare, \-lfreefare)
.\" ____ _
.\" / ___| _ _ _ __ ___ _ __ ___(_)___
.\" \___ \| | | | '_ \ / _ \| '_ \/ __| / __|
.\" ___) | |_| | | | | (_) | |_) \__ \ \__ \
.\" |____/ \__, |_| |_|\___/| .__/|___/_|___/
.\" |___/ |_|
.Sh SYNOPSIS
.In freefare.h
.Ft MifareDESFireKey
.Fn mifare_desfire_des_key_new "uint8_t value[8]"
.Ft MifareDESFireKey
.Fn mifare_desfire_3des_key_new "uint8_t value[16]"
.Ft MifareDESFireKey
.Fn mifare_desfire_des_key_new_with_version "uint8_t value[8]"
.Ft MifareDESFireKey
.Fn mifare_desfire_3des_key_new_with_version "uint8_t value[16]"
.Ft uint8_t
.Fn mifare_desfire_key_get_version "MifareDESFireKey key"
.Ft void
.Fn mifare_desfire_key_set_version "MifareDESFireKey key" "uint8_t version"
.Ft void
.Fn mifare_desfire_key_free "MifareDESFireKey key"
.\" ____ _ _ _
.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __
.\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \
.\" | |_| | __/\__ \ (__| | | | |_) | |_| | (_) | | | |
.\" |____/ \___||___/\___|_| |_| .__/ \__|_|\___/|_| |_|
.\" |_|
.Sh DESCRIPTION
The
.Fn mifare_desfire_key_*
family of functions allows management of Mifare DESFire keys.
.Pp
The
.Fn mifare_desfire_des_key_new
and
.Fn mifare_desfire_3des_key_new
alocate a new key with the provided data
.Va value .
The key version is set to
.Va 0 .
.Pp
The
.Fn mifare_desfire_des_key_new_with_version
and
.Fn mifare_desfire_3des_key_new_with_version
functions are equivalent to the
.Fn mifare_desfire_des_key_new
and
.Fn mifare_desfire_3des_key_new
functions except that the key version is set to
.Va version .
.Pp
The version of a
.Vt MifareDESFireKey
can be extracted using
.Fn mifare_desfire_key_get_version
and changed using
.Fn mifare_desfire_key_set_version.
.Pp
The
.Fn mifare_desfire_key_free
has to be called for each
.Va MifareDESFireKey
after usage to reclaim memory.
.\" ____ _ _
.\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___
.\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __|
.\" | _ < __/ |_| |_| | | | | | | \ V / (_| | | |_| | __/\__ \
.\" |_| \_\___|\__|\__,_|_| |_| |_| \_/ \__,_|_|\__,_|\___||___/
.\"
.Sh RETURN VALUES
Key allocations functions return the allocaed key of
.Va NULL
on failure.
.\" ____ _
.\" / ___| ___ ___ __ _| |___ ___
.\" \___ \ / _ \/ _ \ / _` | / __|/ _ \
.\" ___) | __/ __/ | (_| | \__ \ (_) |
.\" |____/ \___|\___| \__,_|_|___/\___/
.\"
.Sh SEE ALSO
.Xr mifare_desfire 3
.\" _ _ _
.\" / \ _ _| |_| |__ ___ _ __ ___
.\" / _ \| | | | __| '_ \ / _ \| '__/ __|
.\" / ___ \ |_| | |_| | | | (_) | | \__ \
.\" /_/ \_\__,_|\__|_| |_|\___/|_| |___/
.\"
.Sh AUTHORS
.An Romain Tartiere Aq romain@il4p.org

View file

@ -0,0 +1,142 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <stdlib.h>
#include <string.h>
#include <openssl/des.h>
#include <freefare.h>
#include "freefare_internal.h"
static inline void update_key_schedules (MifareDESFireKey key);
static inline void
update_key_schedules (MifareDESFireKey key)
{
DES_set_key ((DES_cblock *)key->data, &(key->ks1));
DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2));
}
MifareDESFireKey
mifare_desfire_des_key_new (uint8_t value[8])
{
uint8_t data[8];
memcpy (data, value, 8);
for (int n=0; n < 8; n++)
data[n] &= 0xfe;
return mifare_desfire_des_key_new_with_version (data);
}
MifareDESFireKey
mifare_desfire_des_key_new_with_version (uint8_t value[8])
{
MifareDESFireKey key;
if ((key = malloc (sizeof (struct mifare_desfire_key)))) {
memcpy (key->data, value, 8);
memcpy (key->data+8, value, 8);
update_key_schedules (key);
key->type = T_DES;
}
return key;
}
MifareDESFireKey
mifare_desfire_3des_key_new (uint8_t value[16])
{
uint8_t data[16];
memcpy (data, value, 16);
for (int n=0; n < 8; n++)
data[n] &= 0xfe;
for (int n=8; n < 16; n++)
data[n] |= 0x01;
return mifare_desfire_3des_key_new_with_version (data);
}
MifareDESFireKey
mifare_desfire_3des_key_new_with_version (uint8_t value[16])
{
MifareDESFireKey key;
if ((key = malloc (sizeof (struct mifare_desfire_key)))) {
memcpy (key->data, value, 16);
update_key_schedules (key);
key->type = T_3DES;
}
return key;
}
uint8_t
mifare_desfire_key_get_version (MifareDESFireKey key)
{
uint8_t version = 0;
for (int n = 0; n < 8; n++) {
version |= ((key->data[n] & 1) << (7 - n));
}
return version;
}
void
mifare_desfire_key_set_version (MifareDESFireKey key, uint8_t version)
{
for (int n = 0; n < 8; n++) {
uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n));
key->data[n] &= 0xfe;
key->data[n] |= version_bit;
if (key->type == T_DES) {
key->data[n+8] = key->data[n];
} else {
// Write ~version to avoid turning a 3DES key into a DES key
key->data[n+8] &= 0xfe;
key->data[n+8] |= ~version_bit;
}
}
}
MifareDESFireKey
mifare_desfire_session_key_new (uint8_t rnda[8], uint8_t rndb[8], MifareDESFireKey authentication_key)
{
MifareDESFireKey key;
uint8_t buffer[16];
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+4, 4);
memcpy (buffer+12, rndb+4, 4);
switch (authentication_key->type) {
case T_DES:
key = mifare_desfire_des_key_new_with_version (buffer);
break;
case T_3DES:
key = mifare_desfire_3des_key_new_with_version (buffer);
break;
}
return key;
}
void
mifare_desfire_key_free (MifareDESFireKey key)
{
free (key);
}

View file

@ -45,6 +45,7 @@ Mifare card manipulation library (libfreefare, \-lfreefare)
.\" |____/ \__, |_| |_|\___/| .__/|___/_|___/
.\" |___/ |_|
.Sh SYNOPSIS
.In freefare.h
.Ft int
.Fn mifare_ultralight_connect "MifareTag tag"
.Ft int

188
libutil.h Normal file
View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 1996 Peter Wemm <peter@FreeBSD.org>.
* All rights reserved.
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* Portions of this software were developed for the FreeBSD Project by
* ThinkSec AS and NAI Labs, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD: stable/8/lib/libutil/libutil.h 185548 2008-12-02 06:50:26Z peter $
*/
#ifndef _LIBUTIL_H_
#define _LIBUTIL_H_
#define PROPERTY_MAX_NAME 64
#define PROPERTY_MAX_VALUE 512
/* for properties.c */
typedef struct _property {
struct _property *next;
char *name;
char *value;
} *properties;
#ifdef _SYS_PARAM_H_
/* for pidfile.c */
struct pidfh {
int pf_fd;
char pf_path[MAXPATHLEN + 1];
__dev_t pf_dev;
ino_t pf_ino;
};
#endif
/* Avoid pulling in all the include files for no need */
struct termios;
struct winsize;
struct utmp;
struct in_addr;
struct kinfo_file;
struct kinfo_vmentry;
__BEGIN_DECLS
void clean_environment(const char * const *_white,
const char * const *_more_white);
int extattr_namespace_to_string(int _attrnamespace, char **_string);
int extattr_string_to_namespace(const char *_string, int *_attrnamespace);
int flopen(const char *_path, int _flags, ...);
void hexdump(const void *ptr, int length, const char *hdr, int flags);
void login(struct utmp *_ut);
int login_tty(int _fd);
int logout(const char *_line);
void logwtmp(const char *_line, const char *_name, const char *_host);
void trimdomain(char *_fullhost, int _hostsize);
int openpty(int *_amaster, int *_aslave, char *_name,
struct termios *_termp, struct winsize *_winp);
int forkpty(int *_amaster, char *_name,
struct termios *_termp, struct winsize *_winp);
int humanize_number(char *_buf, size_t _len, int64_t _number,
const char *_suffix, int _scale, int _flags);
int expand_number(const char *_buf, int64_t *_num);
const char *uu_lockerr(int _uu_lockresult);
int uu_lock(const char *_ttyname);
int uu_unlock(const char *_ttyname);
int uu_lock_txfr(const char *_ttyname, pid_t _pid);
int _secure_path(const char *_path, uid_t _uid, gid_t _gid);
properties properties_read(int fd);
void properties_free(properties list);
char *property_find(properties list, const char *name);
char *auth_getval(const char *name);
int realhostname(char *host, size_t hsize, const struct in_addr *ip);
struct sockaddr;
int realhostname_sa(char *host, size_t hsize, struct sockaddr *addr,
int addrlen);
int kld_isloaded(const char *name);
int kld_load(const char *name);
struct kinfo_file *
kinfo_getfile(pid_t _pid, int *_cntp);
struct kinfo_vmentry *
kinfo_getvmmap(pid_t _pid, int *_cntp);
#ifdef _STDIO_H_ /* avoid adding new includes */
char *fparseln(FILE *, size_t *, size_t *, const char[3], int);
#endif
#ifdef _PWD_H_
int pw_copy(int _ffd, int _tfd, const struct passwd *_pw, struct passwd *_old_pw);
struct passwd *pw_dup(const struct passwd *_pw);
int pw_edit(int _notsetuid);
int pw_equal(const struct passwd *_pw1, const struct passwd *_pw2);
void pw_fini(void);
int pw_init(const char *_dir, const char *_master);
char *pw_make(const struct passwd *_pw);
int pw_mkdb(const char *_user);
int pw_lock(void);
struct passwd *pw_scan(const char *_line, int _flags);
const char *pw_tempname(void);
int pw_tmp(int _mfd);
#endif
#ifdef _GRP_H_
int gr_equal(const struct group *gr1, const struct group *gr2);
char *gr_make(const struct group *gr);
struct group *gr_dup(const struct group *gr);
struct group *gr_scan(const char *line);
#endif
#ifdef _SYS_PARAM_H_
struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);
int pidfile_write(struct pidfh *pfh);
int pidfile_close(struct pidfh *pfh);
int pidfile_remove(struct pidfh *pfh);
#endif
__END_DECLS
#define UU_LOCK_INUSE (1)
#define UU_LOCK_OK (0)
#define UU_LOCK_OPEN_ERR (-1)
#define UU_LOCK_READ_ERR (-2)
#define UU_LOCK_CREAT_ERR (-3)
#define UU_LOCK_WRITE_ERR (-4)
#define UU_LOCK_LINK_ERR (-5)
#define UU_LOCK_TRY_ERR (-6)
#define UU_LOCK_OWNER_ERR (-7)
/* return values from realhostname() */
#define HOSTNAME_FOUND (0)
#define HOSTNAME_INCORRECTNAME (1)
#define HOSTNAME_INVALIDADDR (2)
#define HOSTNAME_INVALIDNAME (3)
/* fparseln(3) */
#define FPARSELN_UNESCESC 0x01
#define FPARSELN_UNESCCONT 0x02
#define FPARSELN_UNESCCOMM 0x04
#define FPARSELN_UNESCREST 0x08
#define FPARSELN_UNESCALL 0x0f
/* pw_scan() */
#define PWSCAN_MASTER 0x01
#define PWSCAN_WARN 0x02
/* humanize_number(3) */
#define HN_DECIMAL 0x01
#define HN_NOSPACE 0x02
#define HN_B 0x04
#define HN_DIVISOR_1000 0x08
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20
/* hexdump(3) */
#define HD_COLUMN_MASK 0xff
#define HD_DELIM_MASK 0xff00
#define HD_OMIT_COUNT (1 << 16)
#define HD_OMIT_HEX (1 << 17)
#define HD_OMIT_CHARS (1 << 18)
#endif /* !_LIBUTIL_H_ */

View file

@ -17,6 +17,9 @@ noinst_LTLIBRARIES = \
test_mifare_classic.la \
test_mifare_classic_create_trailer_block.la \
test_mifare_classic_sector_boundaries.la \
test_mifare_desfire.la \
test_mifare_desfire_des.la \
test_mifare_desfire_key.la \
test_mifare_ultralight.la \
test_tlv.la
@ -40,6 +43,17 @@ test_mifare_classic_sector_boundaries_la_LIBADD = $(top_builddir)/libfreefare/li
test_mifare_classic_create_trailer_block_la_SOURCES = test_mifare_classic_create_trailer_block.c
test_mifare_classic_create_trailer_block_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mifare_desfire_la_SOURCES = test_mifare_desfire.c \
mifare_desfire_fixture.c \
mifare_desfire_fixture.h
test_mifare_desfire_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la -lutil
test_mifare_desfire_des_la_SOURCES = test_mifare_desfire_des.c
test_mifare_desfire_des_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la -lssl
test_mifare_desfire_key_la_SOURCES = test_mifare_desfire_key.c
test_mifare_desfire_key_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mifare_ultralight_la_SOURCES = test_mifare_ultralight.c \
mifare_ultralight_fixture.c \
mifare_ultralight_fixture.h
@ -52,5 +66,6 @@ echo-cutter:
@echo $(CUTTER)
EXTRA_DIST = run-test.sh
CLEANFILES = *.gcno
endif

View file

@ -28,28 +28,39 @@ void
cut_setup ()
{
int res;
nfc_device_desc_t devices[8];
size_t device_count;
device = nfc_connect (NULL);
if (!device)
nfc_list_devices (devices, 8, &device_count);
if (!device_count)
cut_omit ("No device found");
tags = freefare_get_tags (device);
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
for (size_t i = 0; i < device_count; i++) {
tag = NULL;
for (int i=0; tags[i]; i++) {
if ((freefare_get_tag_type(tags[i]) == CLASSIC_1K) ||
(freefare_get_tag_type(tags[i]) == CLASSIC_4K)) {
tag = tags[i];
break;
device = nfc_connect (&(devices[i]));
if (!device)
cut_omit ("nfc_connect() failed");
tags = freefare_get_tags (device);
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
tag = NULL;
for (int i=0; tags[i]; i++) {
if ((freefare_get_tag_type(tags[i]) == CLASSIC_1K) ||
(freefare_get_tag_type(tags[i]) == CLASSIC_4K)) {
tag = tags[i];
res = mifare_classic_connect (tag);
cut_assert_equal_int (0, res, cut_message ("mifare_classic_connect() failed"));
return;
}
}
nfc_disconnect (device);
device = NULL;
freefare_free_tags (tags);
tags = NULL;
}
if (!tag)
cut_omit ("No MIFARE Classic tag on NFC device");
res = mifare_classic_connect (tag);
cut_assert_equal_int (0, res, cut_message ("mifare_classic_connect() failed"));
cut_omit ("No MIFARE Classic tag on NFC device");
}
void
@ -58,8 +69,10 @@ cut_teardown ()
if (tag)
mifare_classic_disconnect (tag);
if (tags)
if (tags) {
freefare_free_tags (tags);
tags = NULL;
}
if (device)
nfc_disconnect (device);

33
test/mifare_desfire_des.c Normal file
View file

@ -0,0 +1,33 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <cutter.h>
#include <freefare.h>
#include "freefare_internal.h"
#include <openssl/des.h>
void
test_mifare_rol8 (void)
{
char data[8] = "01234567";
rol8 (data);
cut_assert_equal_memory (data, 8, "12345670", 8);
}

View file

@ -0,0 +1,79 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <cutter.h>
#include <freefare.h>
static nfc_device_t *device = NULL;
static MifareTag *tags = NULL;
MifareTag tag = NULL;
void
cut_setup ()
{
int res;
nfc_device_desc_t devices[8];
size_t device_count;
nfc_list_devices (devices, 8, &device_count);
if (!device_count)
cut_omit ("No device found");
for (size_t i = 0; i < device_count; i++) {
device = nfc_connect (&(devices[i]));
if (!device)
cut_omit ("nfc_connect() failed");
tags = freefare_get_tags (device);
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
tag = NULL;
for (int i=0; tags[i]; i++) {
if (freefare_get_tag_type(tags[i]) == DESFIRE_4K) {
tag = tags[i];
res = mifare_desfire_connect (tag);
cut_assert_equal_int (0, res, cut_message ("mifare_desfire_connect() failed"));
return;
}
}
nfc_disconnect (device);
device = NULL;
freefare_free_tags (tags);
tags = NULL;
}
cut_omit ("No MIFARE DESFire tag on NFC device");
}
void
cut_teardown ()
{
if (tag)
mifare_desfire_disconnect (tag);
if (tags) {
freefare_free_tags (tags);
tags = NULL;
}
if (device)
nfc_disconnect (device);
}

View file

@ -0,0 +1,20 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
extern MifareTag tag;

View file

@ -28,27 +28,38 @@ void
cut_setup ()
{
int res;
nfc_device_desc_t devices[8];
size_t device_count;
device = nfc_connect (NULL);
if (!device)
nfc_list_devices (devices, 8, &device_count);
if (!device_count)
cut_omit ("No device found");
tags = freefare_get_tags (device);
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
for (size_t i = 0; i < device_count; i++) {
tag = NULL;
for (int i=0; tags[i]; i++) {
if (freefare_get_tag_type(tags[i]) == ULTRALIGHT) {
tag = tags[i];
break;
device = nfc_connect (&(devices[i]));
if (!device)
cut_omit ("nfc_connect() failed");
tags = freefare_get_tags (device);
cut_assert_not_null (tags, cut_message ("freefare_get_tags() failed"));
tag = NULL;
for (int i=0; tags[i]; i++) {
if (freefare_get_tag_type(tags[i]) == ULTRALIGHT) {
tag = tags[i];
res = mifare_ultralight_connect (tag);
cut_assert_equal_int (0, res, cut_message ("mifare_ultralight_connect() failed"));
return;
}
}
nfc_disconnect (device);
device = NULL;
freefare_free_tags (tags);
tags = NULL;
}
if (!tag)
cut_omit ("No MIFARE UltraLight tag on NFC device");
res = mifare_ultralight_connect (tag);
cut_assert_equal_int (0, res, cut_message ("mifare_ultralight_connect() failed"));
cut_omit ("No MIFARE UltraLight tag on NFC device");
}
void
@ -57,8 +68,10 @@ cut_teardown ()
if (tag)
mifare_ultralight_disconnect (tag);
if (tags)
if (tags) {
freefare_free_tags (tags);
tags = NULL;
}
if (device)
nfc_disconnect (device);

View file

@ -27,6 +27,9 @@ test_mifare_application (void)
MadAid aid = { 0x22, 0x42 };
Mad mad = mad_new (2);
int i;
cut_assert_not_null (mad, cut_message ("mad_new() failed"));
MifareClassicSectorNumber *s_alloc = mifare_application_alloc (mad, aid, 3*3*16);
@ -35,12 +38,12 @@ test_mifare_application (void)
MifareClassicSectorNumber *s_found = mifare_application_find (mad, aid);
cut_assert_not_null (s_found, cut_message ("mifare_application_alloc() failed"));
for (int i = 0; i < 3; i++) {
for (i = 0; s_alloc[i]; i++) {
cut_assert_equal_int (s_alloc[i], s_found[i], cut_message ("Allocated and found blocks don't match at position %d", i));
}
cut_assert_equal_int (0, s_alloc[3], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_found[3], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_alloc[i], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_found[i], cut_message ("Invalid size"));
mifare_application_free (mad, aid);
@ -56,12 +59,14 @@ test_mifare_application (void)
s_found = mifare_application_find (mad, aid);
cut_assert_not_null (s_found, cut_message ("mifare_application_alloc() failed"));
for (int i = 0; i < 3; i++) {
for (i = 0; s_alloc[i]; i++) {
cut_assert_equal_int (s_alloc[i], s_found[i], cut_message ("Allocated and found blocks don't match at position %d", i));
}
cut_assert_equal_int (0, s_alloc[3], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_found[3], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_alloc[i], cut_message ("Invalid size"));
cut_assert_equal_int (0, s_found[i], cut_message ("Invalid size"));
mifare_application_free (mad, aid);

View file

@ -19,6 +19,7 @@
#include <cutter.h>
#include <string.h>
#include <strings.h>
#include <freefare.h>
#include "freefare_internal.h"
@ -113,7 +114,7 @@ test_mifare_classic_format (void)
};
MifareClassicBlock empty;
memset (empty, '\x00', sizeof (empty));
bzero (empty, sizeof (empty));
res = mifare_classic_write (tag, 0x3c, data);
cut_assert_equal_int (0, res, cut_message ("mifare_classic_write() failed"));

969
test/test_mifare_desfire.c Normal file
View file

@ -0,0 +1,969 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <cutter.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <freefare.h>
#include "freefare_internal.h"
#include "mifare_desfire_fixture.h"
uint8_t key_data_null[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t key_data_des[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };
uint8_t key_data_3des[16] = { 'C', 'a', 'r', 'd', ' ', 'M', 'a', 's', 't', 'e', 'r', ' ', 'K', 'e', 'y', '!' };
#define cut_assert_success(last_command) \
do { \
if ((res < 0) || (MIFARE_DESFIRE (tag)->last_picc_error != OPERATION_OK)) { \
cut_fail ("%s returned %d, error: %s, errno: %s\n", last_command, res, desfire_error_lookup (MIFARE_DESFIRE (tag)->last_picc_error), strerror (errno)); \
} \
} while (0);
void
test_mifare_desfire (void)
{
int res;
/* Select the master application */
res = mifare_desfire_select_application (tag, NULL);
cut_assert_success ("mifare_desfire_select_application()");
/* Get version information */
struct mifare_desfire_version_info version_info;
res = mifare_desfire_get_version (tag, &version_info);
cut_assert_success ("mifare_desfire_get_version()");
/* Determine which key is currently the master one */
uint8_t key_version;
res = mifare_desfire_get_key_version (tag, 0, &key_version);
cut_assert_success ("mifare_desfire_get_key_version()");
MifareDESFireKey key;
switch (key_version) {
case 0x00:
key = mifare_desfire_des_key_new_with_version (key_data_null);
break;
case 0xAA:
key = mifare_desfire_des_key_new_with_version (key_data_des);
break;
case 0xC7:
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
break;
default:
cut_fail ("Unknown master key.");
}
cut_assert_not_null (key, cut_message ("Cannot allocate key"));
/* Authenticate with this key */
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
/*
* This unit test change key settings to more restrictive ones, so reset
* them to factory defaults in case the previous run failed unexpectedly.
*/
res = mifare_desfire_change_key_settings (tag, 0xF);
cut_assert_success ("mifare_desfire_change_key_settings()");
/* Change master key to DES */
key = mifare_desfire_des_key_new_with_version (key_data_des);
mifare_desfire_change_key (tag, 0, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
res = mifare_desfire_get_key_version (tag, 0, &key_version);
cut_assert_success ("mifare_desfire_get_key_version()");
cut_assert_equal_int (0xAA, key_version, cut_message ("Wrong key_version value."));
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
/* Change master key to 3DES */
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
mifare_desfire_change_key (tag, 0, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
res = mifare_desfire_get_key_version (tag, 0, &key_version);
cut_assert_success ("mifare_desfire_get_key_version()");
cut_assert_equal_int (0xC7, key_version, cut_message ("Wrong key_version value."));
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
/* Wipeout the card */
res = mifare_desfire_format_picc (tag);
cut_assert_success ("mifare_desfire_format_picc()");
/* Create 3 applications */
res = mifare_desfire_select_application (tag, NULL);
cut_assert_success ("mifare_desfire_select_application()");
MifareDESFireAID aid_a = mifare_desfire_aid_new (0xAA, 0xAA, 0xA);
cut_assert_not_null (aid_a, cut_message ("Cannot allocate AID"));
#ifdef SNAPPER
// FIXME: For some reason, 0xFF fails
res = mifare_desfire_create_application (tag, aid_a, 0xEF, 0);
#else
res = mifare_desfire_create_application (tag, aid_a, 0xFF, 0);
#endif
cut_assert_success ("mifare_desfire_create_application()");
MifareDESFireAID aid_b = mifare_desfire_aid_new (0xBB, 0xBB, 0xB);
cut_assert_not_null (aid_b, cut_message ("Cannot allocate AID"));
res = mifare_desfire_create_application (tag, aid_b, 0xEF, 6);
cut_assert_success ("mifare_desfire_create_application()");
#ifdef SNAPPER
// FIXME: For some reason 0xCC CC C fails when authenticating
MifareDESFireAID aid_c = mifare_desfire_aid_new (0x12, 0x34, 0x5);
#else
MifareDESFireAID aid_c = mifare_desfire_aid_new (0xCC, 0xCC, 0xC);
#endif
cut_assert_not_null (aid_c, cut_message ("Cannot allocate AID"));
res = mifare_desfire_create_application (tag, aid_c, 0xC2, 14);
cut_assert_success ("mifare_desfire_create_application()");
// Ensure we can find the created applications
MifareDESFireAID *aids = NULL;
size_t aid_count;
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_success ("mifare_desfire_get_application_ids()");
cut_assert_equal_int (3, aid_count, cut_message ("Wrong application count"));
mifare_desfire_free_application_ids (aids);
// Create files in the application A
res = mifare_desfire_select_application (tag, aid_a);
cut_assert_success ("mifare_desfire_select_application()");
uint8_t std_data_file_id = 15;
res = mifare_desfire_create_std_data_file (tag, std_data_file_id, MDCM_PLAIN, 0xEEEE, 100);
cut_assert_success ("mifare_desfire_create_std_data_file()");
res = mifare_desfire_create_backup_data_file (tag, 5, MDCM_PLAIN, 0xEEEE, 64);
cut_assert_success ("mifare_desfire_create_backup_data_file()");
res = mifare_desfire_create_value_file (tag, 4, MDCM_PLAIN, 0xEEEE, 0, 1000, 0, 0);
cut_assert_success ("mifare_desfire_create_value_file()");
res = mifare_desfire_create_cyclic_record_file (tag, 0, MDCM_PLAIN, 0xEEEE, 4, 10);
cut_assert_success ("mifare_desfire_create_cyclic_record_file()");
// Write some data in the standard data file
res = mifare_desfire_write_data (tag, std_data_file_id, 0, 30, (uint8_t *)"Some data to write to the card");
cut_assert_success ("mifare_desfire_write_data()");
cut_assert_equal_int (30, res, cut_message ("Wrong number of bytes writen"));
res = mifare_desfire_write_data (tag, std_data_file_id, 34, 22, (uint8_t *)"Another block of data.");
cut_assert_success ("mifare_desfire_write_data()");
cut_assert_equal_int (22, res, cut_message ("Wrong number of bytes writen"));
// Make the file read-only
res = mifare_desfire_change_file_settings (tag, std_data_file_id, MDCM_PLAIN, 0xEFFF);
cut_assert_success ("mifare_desfire_change_file_settings()");
// Read a part of the file
uint8_t buffer[120];
res = mifare_desfire_read_data (tag, std_data_file_id, 10, 50, &buffer);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (50, res, cut_message ("Wrong number of bytes read"));
cut_assert_equal_memory ("to write to the card\0\0\0\0Another block of data.\0\0\0\0", 50, buffer, 50, cut_message ("Wrong data"));
// Read all the file at once
res = mifare_desfire_read_data (tag, std_data_file_id, 0, 0, &buffer);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (100, res, cut_message ("Wrong number of bytes read"));
cut_assert_equal_memory ("Some data to write to the"
" card\0\0\0\0Another block of"
" data.\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 100, buffer, 100, cut_message ("Wrong data"));
// Try to overwrute the file
res = mifare_desfire_write_data (tag, std_data_file_id, 20, 5, (char *)"Test!");
cut_assert_equal_int (-1, res, cut_message ("Wrong return value"));
cut_assert_equal_int (PERMISSION_ERROR, MIFARE_DESFIRE (tag)->last_picc_error, cut_message ("Wrong PICC error"));
int32_t expected_value = 0;
for (int transaction = 0; transaction < 15; transaction++) {
char data_buffer[3];
sprintf (data_buffer, "%02d", transaction);
// Write to the backup file
res = mifare_desfire_write_data (tag, 5, 3*transaction, 3, data_buffer);
cut_assert_success ("mifare_desfire_write_data()");
// Manipulate the value file
res = mifare_desfire_credit (tag, 4, 100);
cut_assert_success ("mifare_desfire_credit()");
res = mifare_desfire_debit (tag, 4, 97);
cut_assert_success ("mifare_desfire_debit()");
// Write to the cyclic record file
res = mifare_desfire_write_record (tag, 0, 2, 2, data_buffer);
cut_assert_success ("mifare_desfire_write_record()");
// Overwrite the cyclic record file
res = mifare_desfire_write_record (tag, 0, 0, 2, (char *)"r.");
cut_assert_success("mifare_desfire_write_record()");
// Ensure that no content was changed yet
char ref_buffer[64];
bzero (ref_buffer, sizeof (ref_buffer));
for (int n = 0; n < transaction; n++) {
sprintf (ref_buffer + 3 * n, "%02d", n);
}
res = mifare_desfire_read_data (tag, 5, 0, 0, buffer);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (64, res, cut_message ("Wrong number of bytes read"));
cut_assert_equal_memory (buffer, 64, ref_buffer, 64, cut_message ("Wrong data"));
int32_t value;
res = mifare_desfire_get_value (tag, 4, &value);
cut_assert_success ("mifare_desfire_get_value()");
cut_assert_equal_int (expected_value, value, cut_message ("Wrong value"));
// Reading records from an empty file would abort the transaction
if (0 != transaction) {
// Get the latest record
res = mifare_desfire_read_records (tag, 0, 0, 1, buffer);
cut_assert_success ("mifare_desfire_read_records()");
sprintf (ref_buffer, "r.%02d", transaction);
cut_assert_not_equal_memory (ref_buffer, 4, buffer, res, cut_message ("Wrong data"));
}
// Commit !
res = mifare_desfire_commit_transaction (tag);
cut_assert_success ("mifare_desfire_commit_transaction()");
res = mifare_desfire_read_data (tag, 5, 3*transaction, 3, buffer);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_memory (data_buffer, 3, buffer, res, cut_message ("Wrong data"));
expected_value += 3;
res = mifare_desfire_get_value (tag, 4, &value);
cut_assert_success ("mifare_desfire_get_value()");
cut_assert_equal_int (expected_value, value, cut_message ("Wrong value"));
res = mifare_desfire_read_records (tag, 0, 0, 1, buffer);
cut_assert_success ("mifare_desfire_read_records()");
sprintf (ref_buffer, "r.%02d", transaction);
cut_assert_equal_memory (ref_buffer, 4, buffer, res, cut_message ("Wrong data"));
}
// Ensure limited credit is disabled
res = mifare_desfire_limited_credit (tag, 4, 20);
cut_assert_equal_int (-1, res, cut_message ("mifare_desfire_limited_credit() should fail"));
// Get all files
uint8_t *files;
size_t file_count;
res = mifare_desfire_get_file_ids (tag, &files, &file_count);
cut_assert_success ("mifare_desfire_get_file_ids()");
cut_assert_equal_int (4, file_count, cut_message ("Wrong number of files"));
for (size_t i=0; i<file_count;i++) {
if ((files[i] != 0) && (files[i] != 4) &&
(files[i] != 5) && (files[i] != 15)) {
cut_fail ("File %d should not exist.", files[i]);
}
struct mifare_desfire_file_settings settings;
res = mifare_desfire_get_file_settings (tag, files[i], &settings);
cut_assert_success ("mifare_desfire_get_file_settings()");
switch (files[i]) {
case 0:
cut_assert_equal_int (MDFT_CYCLIC_RECORD_FILE_WITH_BACKUP, settings.file_type, cut_message ("Wrong file type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("Wrong communication settings"));
cut_assert_equal_int (4, settings.settings.linear_record_file.record_size, cut_message ("Wrong record size"));
cut_assert_equal_int (10, settings.settings.linear_record_file.max_number_of_records, cut_message ("Wrong max number of records"));
cut_assert_equal_int (9, settings.settings.linear_record_file.current_number_of_records, cut_message ("Wrong current number of records"));
break;
case 4:
cut_assert_equal_int (MDFT_VALUE_FILE_WITH_BACKUP, settings.file_type, cut_message ("Wrong file type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("Wrong communication settings"));
cut_assert_equal_int (0, settings.settings.value_file.lower_limit, cut_message ("Wrong lower limit"));
cut_assert_equal_int (1000, settings.settings.value_file.upper_limit, cut_message ("Wrong upper limit"));
cut_assert_equal_int (97, settings.settings.value_file.limited_credit_value, cut_message ("Wrong limited_credit value"));
cut_assert_equal_int (0, settings.settings.value_file.limited_credit_enabled, cut_message ("Wrong limited_credit enable state"));
break;
case 5:
cut_assert_equal_int (MDFT_BACKUP_DATA_FILE, settings.file_type, cut_message ("Wrong file type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("Wrong communication settings"));
cut_assert_equal_int (64, settings.settings.standard_file.file_size, cut_message ("Wrong file size"));
break;
case 15:
cut_assert_equal_int (MDFT_STANDARD_DATA_FILE, settings.file_type, cut_message ("Wrong file type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("Wrong communication settings"));
cut_assert_equal_int (100, settings.settings.standard_file.file_size, cut_message ("Wrong file size"));
break;
default:
cut_fail ("Wow! Cosmic ray!");
}
res = mifare_desfire_delete_file (tag, files[i]);
cut_assert_success ("mifare_desfire_delete_file()");
}
free (files);
// All files should have been removed
res = mifare_desfire_get_file_ids (tag, &files, &file_count);
cut_assert_success ("mifare_desfire_get_file_ids()");
cut_assert_equal_int (0, file_count, cut_message ("Wrong number of files"));
// Delete application A
res = mifare_desfire_select_application (tag, 0);
cut_assert_success ("mifare_desfire_select_application()");
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_delete_application (tag, aid_a);
cut_assert_success ("mifare_desfire_delete_application()");
// Ensure application A was deleted
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_success ("mifare_desfire_get_application_ids()");
cut_assert_equal_int (2, aid_count, cut_message ("Wrong application count"));
mifare_desfire_free_application_ids (aids);
// Change application B keys
res = mifare_desfire_select_application (tag, aid_b);
cut_assert_success ("mifare_desfire_select_application()");
key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
// Use a 3DES application master key
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Master Key");
res = mifare_desfire_change_key (tag, 0, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
/* Authenticate with the new master key */
/* (Reversed parity bits this time) */
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "@pp/C!L`ruds!Kdx");
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_get_key_version (tag, 0, &key_version);
cut_assert_success ("mifare_desfire_get_key_version()");
// App.B Mas-ter Key
// 0b100000111-0100111
// 0x 83- A7
cut_assert_equal_int (0x83, key_version, cut_message ("Wrong key version"));
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Master Key");
cut_assert_equal_int (0x83, mifare_desfire_key_get_version (key), cut_message ("mifare_desfire_key_get_version() returns an invalid version"));
mifare_desfire_key_free (key);
/* Change key #1 */
key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 1, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
key = mifare_desfire_des_key_new_with_version ((uint8_t *) "SglDES_1");
res = mifare_desfire_change_key (tag, 1, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
/* Change key #5 */
key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 5, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "B's Chg Keys Key");
res = mifare_desfire_change_key (tag, 5, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
/* Set key #5 as the change key */
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Master Key");
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_change_key_settings (tag, 0x5F);
cut_assert_success ("mifare_desfire_change_key_settings()");
uint8_t key_settings;
uint8_t max_keys;
res = mifare_desfire_get_key_settings (tag, &key_settings, &max_keys);
cut_assert_success ("mifare_desfire_get_key_settings()");
cut_assert_equal_int (0x5F, key_settings, cut_message ("Wrong key settings"));
cut_assert_equal_int (6, max_keys, cut_message ("Wrong maximum number of keys"));
/* Change key #1 to #4 using the three key procedure. */
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "B's Chg Keys Key");
res = mifare_desfire_authenticate (tag, 5, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.B Key #1. ");
MifareDESFireKey key1 = mifare_desfire_des_key_new_with_version ((uint8_t *) "SglDES_1");
res = mifare_desfire_change_key (tag, 1, key, key1);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
mifare_desfire_key_free (key1);
key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.B Key #2.. ");
res = mifare_desfire_change_key (tag, 2, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.B Key #3... ");
res = mifare_desfire_change_key (tag, 3, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.B Key #4....");
res = mifare_desfire_change_key (tag, 4, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (key);
std_data_file_id--;
res = mifare_desfire_create_std_data_file (tag, std_data_file_id, MDCM_PLAIN, 0x1234, 100);
cut_assert_success ("mifare_desfire_create_std_data_file()");
expected_value = -1000000;
res = mifare_desfire_create_value_file (tag, 4, 0, 0x1324, -987654321, -1000, expected_value, 1);
cut_assert_success ("mifare_desfire_create_value_file()");
res = mifare_desfire_create_linear_record_file (tag, 1, 0, 0x1324, 25, 4);
int nr = 0;
for (int transaction = 0; transaction < 7; transaction++) {
uint8_t cs = transaction % 3;
if (cs == 2) cs++;
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Key #4....");
res = mifare_desfire_authenticate (tag, 4, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_change_file_settings (tag, std_data_file_id, cs, 0x1234);
cut_assert_success ("mifare_desfire_change_file_settings()");
res = mifare_desfire_change_file_settings (tag, 4, cs, 0x1324);
cut_assert_success ("mifare_desfire_change_file_settings()");
res = mifare_desfire_change_file_settings (tag, 1, cs, 0x1324);
cut_assert_success ("mifare_desfire_change_file_settings()");
// Authenticate witht he write key
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Key #2.. ");
res = mifare_desfire_authenticate (tag, 2, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
char data_buffer[100];
char data_buffer2[100];
char data_buffer3[100];
for (int i = 0; i < 100; i++)
data_buffer[i] = transaction + i;
res = mifare_desfire_write_data (tag, std_data_file_id, 0, 100, data_buffer);
cut_assert_success ("mifare_desfire_write_data()");
sprintf (data_buffer2, "Transaction #%d", transaction);
res = mifare_desfire_write_data (tag, std_data_file_id, 5, strlen (data_buffer2), data_buffer2);
cut_assert_success ("mifare_desfire_write_data()");
memcpy (data_buffer + 5, data_buffer2, strlen (data_buffer2));
// Write to the linear record. When it's full, erase it and restart.
for (int i = 0; i < 2; i++) {
if ((transaction % 2 == 1) && (i == 1)) {
res = mifare_desfire_clear_record_file (tag, 1);
cut_assert_success ("mifare_desfire_clear_record_file()");
sprintf (data_buffer3, "Test invalid write");
res = mifare_desfire_write_record (tag, 1, 0, strlen (data_buffer3), data_buffer3);
cut_assert_equal_int (-1, res, cut_message ("error code"));
cut_assert_equal_int (PERMISSION_ERROR, MIFARE_DESFIRE (tag)->last_picc_error, cut_message ("PICC error"));
// The prebious failure has aborted the transaction, so clear
// record again.
res = mifare_desfire_clear_record_file (tag, 1);
cut_assert_success ("mifare_desfire_clear_record_file()");
res = mifare_desfire_commit_transaction (tag);
cut_assert_success ("mifare_desfire_commit_transaction()");
nr = 0;
}
res = mifare_desfire_write_record (tag, 1, 0, 25, "0123456789012345678901234");
cut_assert_success ("mifare_desfire_write_record()");
res = mifare_desfire_write_record (tag, 1, 5, strlen (data_buffer2), data_buffer2);
cut_assert_success ("mifare_desfire_write_record()");
}
nr++;
// Modify the value file
res = mifare_desfire_debit (tag, 4, 1300);
cut_assert_success ("mifare_desfire_debit()");
expected_value -= 1300;
res = mifare_desfire_credit (tag, 4, 20);
cut_assert_success ("mifare_desfire_credit()");
expected_value += 20;
res = mifare_desfire_debit (tag, 4, 1700);
cut_assert_success ("mifare_desfire_debit()");
expected_value -= 1700;
// Commit
res = mifare_desfire_commit_transaction (tag);
cut_assert_success ("mifare_desfire_commit_transaction()");
// Refund the whole debited amount
res = mifare_desfire_limited_credit (tag, 4, 3000);
cut_assert_success ("mifare_desfire_limited_credit()");
expected_value += 3000;
// Commit
res = mifare_desfire_commit_transaction (tag);
cut_assert_success ("mifare_desfire_commit_transaction()");
// Authenticate with the key that allows reading
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Key #1. ");
res = mifare_desfire_authenticate (tag, 1, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
// Read first half of the file
res = mifare_desfire_read_data (tag, std_data_file_id, 0, 50, data_buffer3);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (50, res, cut_message ("length"));
cut_assert_equal_memory (data_buffer, 50, data_buffer3, res, cut_message ("data"));
// Read second half of the file
res = mifare_desfire_read_data (tag, std_data_file_id, 50, 0, data_buffer3);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (50, res, cut_message ("length"));
cut_assert_equal_memory (data_buffer + 50, 50, data_buffer3, res, cut_message ("data"));
// Get the value file current balance
int32_t value;
res = mifare_desfire_get_value (tag, 4, &value);
cut_assert_success ("mifare_desfire_get_value()");
cut_assert_equal_int (expected_value, value, cut_message ("value"));
// Get the number of records in the linear record file
struct mifare_desfire_file_settings settings;
res = mifare_desfire_get_file_settings (tag, 1, &settings);
cut_assert_success ("mifare_desfire_get_file_settings()");
cut_assert_equal_int (MDFT_LINEAR_RECORD_FILE_WITH_BACKUP, settings.file_type, cut_message ("settings"));
cut_assert_equal_int (nr, settings.settings.linear_record_file.current_number_of_records, cut_message ("settings"));
// Read the oldest record
res = mifare_desfire_read_records (tag, 1, nr - 1, 1, data_buffer3);
cut_assert_success ("mifare_desfire_read_records()");
cut_assert_equal_int (25, res, cut_message ("length"));
sprintf (data_buffer, "0123456789012345678901234");
sprintf (data_buffer2, "Transaction #%d", transaction - nr + 1);
memcpy ((uint8_t *)data_buffer + 5, data_buffer2, strlen (data_buffer2));
cut_assert_equal_memory (data_buffer, strlen (data_buffer), data_buffer3, res, cut_message ("data"));
// Read all records
res = mifare_desfire_read_records (tag, 1, 0, 0, data_buffer3);
cut_assert_success ("mifare_desfire_read_records()");
cut_assert_equal_int (25 * nr, res, cut_message ("length"));
}
res = mifare_desfire_get_file_ids (tag, &files, &file_count);
cut_assert_success ("mifare_desfire_get_file_ids");
cut_assert_equal_int (3, file_count, cut_message ("count"));
for (size_t i = 0; i < file_count; i++) {
struct mifare_desfire_file_settings settings;
res = mifare_desfire_get_file_settings (tag, files[i], &settings);
cut_assert_success ("mifare_desfire_get_file_settings()");
switch (files[i]) {
case 1:
cut_assert_equal_int (MDFT_LINEAR_RECORD_FILE_WITH_BACKUP, settings.file_type, cut_message ("type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("cs"));
cut_assert_equal_int (0x1324, settings.access_rights, cut_message ("access_rights"));
cut_assert_equal_int (25, settings.settings.linear_record_file.record_size, cut_message ("record_size"));
cut_assert_equal_int (4, settings.settings.linear_record_file.max_number_of_records, cut_message ("max_number_of_records"));
cut_assert_equal_int (2, settings.settings.linear_record_file.current_number_of_records, cut_message ("current_number_of_records"));
break;
case 4:
cut_assert_equal_int (MDFT_VALUE_FILE_WITH_BACKUP , settings.file_type, cut_message ("type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("cs"));
cut_assert_equal_int (0x1324, settings.access_rights, cut_message ("access_rights"));
cut_assert_equal_int (-987654321, settings.settings.value_file.lower_limit, cut_message ("lower_limit"));
cut_assert_equal_int (-1000, settings.settings.value_file.upper_limit, cut_message ("upper_limit"));
cut_assert_equal_int (0, settings.settings.value_file.limited_credit_value, cut_message ("limited_credit_value"));
cut_assert_equal_int (1, settings.settings.value_file.limited_credit_enabled, cut_message ("limited_credit_enabled"));
break;
case 14: /* std_data_file_id */
cut_assert_equal_int (MDFT_STANDARD_DATA_FILE, settings.file_type, cut_message ("type"));
cut_assert_equal_int (MDCM_PLAIN, settings.communication_settings, cut_message ("cs"));
cut_assert_equal_int (0x1234, settings.access_rights, cut_message ("access_rights"));
cut_assert_equal_int (100, settings.settings.standard_file.file_size, cut_message ("size"));
break;
default:
cut_fail ("file_no");
}
res = mifare_desfire_delete_file (tag, files[i]);
cut_assert_success ("mifare_desfire_delete_file()");
}
free (files);
// Check there are no files anymore
res = mifare_desfire_get_file_ids (tag, &files, &file_count);
cut_assert_success ("mifare_desfire_get_file_ids");
cut_assert_equal_int (0, file_count, cut_message ("count"));
/* Delete application B */
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.B Master Key");
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_delete_application (tag, aid_b);
cut_assert_success ("mifare_desfire_delete_application()");
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_success ("mifare_desfire_get_application_ids()");
cut_assert_equal_int (1, aid_count, cut_message ("Wrong AID count"));
mifare_desfire_free_application_ids (aids);
/* Tests using application C */
res = mifare_desfire_select_application (tag, aid_c);
cut_assert_success ("mifare_desfire_select_application()");
key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 12, key);
cut_assert_success ("mifare_desfire_authenticate()");
MifareDESFireKey new_key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.C Key #1. ");
res = mifare_desfire_change_key (tag, 1, new_key, key);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (new_key);
new_key = mifare_desfire_3des_key_new_with_version ((uint8_t *)"App.C Key #2.. ");
res = mifare_desfire_change_key (tag, 2, new_key, key);
cut_assert_success ("mifare_desfire_change_key()");
mifare_desfire_key_free (new_key);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_create_cyclic_record_file (tag, 6, MDCM_PLAIN, 0x12E0, 100, 22);
cut_assert_success ("mifare_desfire_create_cyclic_record_file()");
for (int transaction = 0; transaction < 50; transaction++) {
char data_buffer[100];
char read_buffer[100];
uint8_t cs = transaction % 3;
if (cs == 2) cs++;
key = mifare_desfire_des_key_new (key_data_null);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_change_file_settings (tag, 6, cs, 0x12E0);
cut_assert_success ("mifare_desfire_change_file_settings()");
if (transaction & 4) {
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.C Key #2.. ");
res = mifare_desfire_authenticate (tag, 2, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
} else {
cs = 0;
}
memset (data_buffer, '_', 100);
data_buffer[0] = transaction;
data_buffer[99] = transaction;
sprintf (data_buffer + 5, " Transaction #%d ", transaction);
res = mifare_desfire_write_record (tag, 6, 0, 100, data_buffer);
cut_assert_success ("mifare_desfire_write_record()");
if (transaction & 4) {
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.C Key #1. ");
res = mifare_desfire_authenticate (tag, 1, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
}
if (transaction % 7 == 0) {
res = mifare_desfire_abort_transaction (tag);
cut_assert_success ("mifare_desfire_abort_transaction()");
ssize_t n = mifare_desfire_read_records (tag, 6, 0, 1, read_buffer);
if (transaction == 0) {
cut_assert_equal_int (-1, n, cut_message ("Wrong return value"));
} else {
cut_assert_equal_int (100, n, cut_message ("Wrong return value"));
cut_assert_not_equal_memory (data_buffer, sizeof (data_buffer), read_buffer, sizeof (read_buffer), cut_message ("Wrong data"));
}
} else {
res = mifare_desfire_commit_transaction (tag);
cut_assert_success ("mifare_desfire_commit_transaction()");
ssize_t n = mifare_desfire_read_records (tag, 6, 0, 1, read_buffer);
cut_assert_equal_int (100, n, cut_message ("Wrong return value"));
cut_assert_equal_memory (data_buffer, sizeof (data_buffer), read_buffer, sizeof (read_buffer), cut_message ("Wrong data"));
}
}
// Read each record
key = mifare_desfire_3des_key_new_with_version ((uint8_t *) "App.C Key #1. ");
res = mifare_desfire_authenticate (tag, 1, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
int t = 49;
for (int i = 0; i < 22; i++) {
char data_buffer[100];
char ref_data_buffer[100];
if (0 == (t % 7))
t--;
memset (ref_data_buffer, '_', 100);
ref_data_buffer[0] = t;
ref_data_buffer[99] = t;
sprintf (ref_data_buffer + 5, " Transaction #%d ", t);
res = mifare_desfire_read_records (tag, 6, i, 1, data_buffer);
if (i == 21) {
cut_assert_equal_int (-1, res, cut_message ("return value"));
} else {
cut_assert_success ("mifare_desfire_read_records()");
cut_assert_equal_memory (ref_data_buffer, 100, data_buffer, res, cut_message ("data"));
}
t--;
}
/*
* Change master key settings to require master key authentication for all
* card operations. Only allow to revert this.
*/
res = mifare_desfire_select_application (tag, 0);
cut_assert_success ("mifare_desfire_select_application()");
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_change_key_settings (tag, 0x08);
cut_assert_success ("mifare_desfire_change_key_settings()");
/* Clear authentication */
res = mifare_desfire_select_application (tag, 0);
cut_assert_success ("mifare_desfire_select_application()");
/* We should not be able to list applications now */
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_equal_int (-1, res, cut_message ("Wrong return value"));
cut_assert_equal_int (AUTHENTICATION_ERROR, MIFARE_DESFIRE (tag)->last_picc_error, cut_message ("Wrong PICC error"));
/* Deleting an application should not be possible */
res = mifare_desfire_delete_application (tag, aid_c);
cut_assert_equal_int (-1, res, cut_message ("Wrong return value"));
cut_assert_equal_int (AUTHENTICATION_ERROR, MIFARE_DESFIRE (tag)->last_picc_error, cut_message ("Wrong PICC error"));
/* Creating an application should also be forbidden */
MifareDESFireAID aid_d = mifare_desfire_aid_new (0xDD, 0xDD, 0xD);
res = mifare_desfire_create_application (tag, aid_d, 0xEF, 0);
cut_assert_equal_int (-1, res, cut_message ("Wrong return value"));
cut_assert_equal_int (AUTHENTICATION_ERROR, MIFARE_DESFIRE (tag)->last_picc_error, cut_message ("Wrong PICC error"));
/*
* Now we retry authenticated with the master key.
*/
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
/* We should be able to list applications again */
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_success ("mifare_desfire_get_application_ids()");
cut_assert_equal_int (1, aid_count, cut_message ("Wrong AID count"));
mifare_desfire_free_application_ids (aids);
/* Deleting an application should be possible again */
res = mifare_desfire_delete_application (tag, aid_c);
cut_assert_success ("mifare_desfire_delete_application()");
/* Creating an application should also be possible */
res = mifare_desfire_create_application (tag, aid_d, 0xEF, 0);
cut_assert_success ("mifare_desfire_create_application()");
/* Revert master key settings to default */
res = mifare_desfire_change_key_settings (tag, 0xF);
cut_assert_success ("mifare_desfire_change_key_settings()");
/* Change the master key back to the default one */
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_change_key (tag, 0, key, NULL);
cut_assert_success ("mifare_desfire_change_key()");
/*
* Delete everything from the card
*/
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
res = mifare_desfire_format_picc (tag);
cut_assert_success ("mifare_desfire_format_picc()");
free (aid_a);
free (aid_b);
free (aid_c);
free (aid_d);
}
void
test_mifare_desfire_get_tag_friendly_name (void)
{
const char *name = freefare_get_tag_friendly_name (tag);
cut_assert_not_null (name, cut_message ("freefare_get_tag_friendly_name() failed"));
}
#define NAID 28
void
test_mifare_desfire_get_many_application_ids (void)
{
int res;
MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
mifare_desfire_key_free (key);
/* Wipeout the card */
res = mifare_desfire_format_picc (tag);
cut_assert_success ("mifare_desfire_format_picc()");
for (int i = 0; i < NAID; i++) {
MifareDESFireAID aid = mifare_desfire_aid_new (i, i, i % 0x10);
res = mifare_desfire_create_application (tag, aid, 0xff, 0);
cut_assert_success ("mifare_desfire_create_application()");
free (aid);
}
MifareDESFireAID *aids;
size_t aid_count;
res = mifare_desfire_get_application_ids (tag, &aids, &aid_count);
cut_assert_success ("mifare_desfire_get_application_ids()");
cut_assert_equal_int (NAID, aid_count, cut_message ("count"));
mifare_desfire_free_application_ids (aids);
/* Wipeout the card */
res = mifare_desfire_format_picc (tag);
cut_assert_success ("mifare_desfire_format_picc()");
}
void
test_mifare_desfire_des_macing(void)
{
int res;
MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data_null);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
MifareDESFireAID aid = mifare_desfire_aid_new (0x12, 0x34, 0x5);
res = mifare_desfire_create_application (tag, aid, 0xFF, 1);
cut_assert_success ("mifare_desfire_create_application()");
res = mifare_desfire_select_application (tag, aid);
cut_assert_success ("mifare_desfire_select_application");
free (aid);
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
res = mifare_desfire_create_std_data_file (tag, 1, MDCM_MACING, 0x0000, 20);
cut_assert_success ("mifare_desfire_create_std_data_file()");
char *s= "Hello World";
res = mifare_desfire_write_data (tag, 1, 0, strlen (s), s);
cut_assert_success ("mifare_desfire_write_data()");
char buffer[20];
res = mifare_desfire_read_data (tag, 1, 0, 0, buffer);
cut_assert_success ("mifare_desfire_read_data()");
cut_assert_equal_int (20, res, cut_message ("retval"));
cut_assert_equal_string (s, buffer, cut_message ("value"));
res = mifare_desfire_select_application (tag, NULL);
cut_assert_success ("mifare_desfire_select_application");
res = mifare_desfire_authenticate (tag, 0, key);
cut_assert_success ("mifare_desfire_authenticate()");
/* Wipeout the card */
res = mifare_desfire_format_picc (tag);
cut_assert_success ("mifare_desfire_format_picc()");
mifare_desfire_key_free (key);
}

View file

@ -0,0 +1,67 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <cutter.h>
#include <freefare.h>
#include "freefare_internal.h"
void
test_mifare_rol8 (void)
{
uint8_t data[8] = "01234567";
rol8 (data);
cut_assert_equal_memory ("12345670", 8, data, 8, cut_message ("Wrong data"));
}
void
test_mifare_desfire_des_receive (void)
{
uint8_t data[8] = { 0xd6, 0x59, 0xe1, 0x70, 0x43, 0xa8, 0x40, 0x68 };
uint8_t key_data[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data);
uint8_t expected_data[8] = { 0x73, 0x0d, 0xdf, 0xad, 0xa4, 0xd2, 0x07, 0x89 };
uint8_t expected_key[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
mifare_cbc_des (key, data, 8, MD_RECEIVE, 0);
cut_assert_equal_memory (&expected_data, 8, &data, 8, cut_message ("Wrong data"));
cut_assert_equal_memory (&expected_key, 8, key->data, 8, cut_message ("Wrong key"));
mifare_desfire_key_free (key);
}
void
test_mifare_desfire_des_send (void)
{
uint8_t data[8] = { 0x73, 0x0d, 0xdf, 0xad, 0xa4, 0xd2, 0x07, 0x89 };
uint8_t key_data[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data);
uint8_t expected_data[8] = { 0xd6, 0x59, 0xe1, 0x70, 0x43, 0xa8, 0x40, 0x68 };
uint8_t expected_key[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
mifare_cbc_des (key, data, 8, MD_SEND, 0);
cut_assert_equal_memory (&expected_data, 8, &data, 8, cut_message ("Wrong data"));
cut_assert_equal_memory (&expected_key, 8, key->data, 8, cut_message ("Wrong key"));
mifare_desfire_key_free (key);
}

View file

@ -0,0 +1,98 @@
/*-
* 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 <http://www.gnu.org/licenses/>
*
* $Id$
*/
#include <cutter.h>
#include <freefare.h>
void
test_mifare_desfire_key (void)
{
MifareDESFireKey key;
int version;
uint8_t key1_des_data[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
key = mifare_desfire_des_key_new (key1_des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
key = mifare_desfire_des_key_new_with_version (key1_des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x55, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_set_version (key, 0xaa);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0xaa, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
uint8_t key2_des_data[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
key = mifare_desfire_des_key_new (key2_des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
key = mifare_desfire_des_key_new_with_version (key2_des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
uint8_t key1_3des_data[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0XEE, 0xFF };
key = mifare_desfire_3des_key_new (key1_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version (key1_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x55, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_set_version (key, 0xaa);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0xaa, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
uint8_t key2_3des_data[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0X01, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
key = mifare_desfire_3des_key_new (key2_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version (key2_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x02, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
uint8_t key3_3des_data[16] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0X00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77 };
key = mifare_desfire_3des_key_new (key3_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x00, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
key = mifare_desfire_3des_key_new_with_version (key3_3des_data);
version = mifare_desfire_key_get_version (key);
cut_assert_equal_int (0x10, version, cut_message ("Wrong MifareDESFireKey version"));
mifare_desfire_key_free (key);
}