From dbd3682174e4686aa6b8cff3b1cb097adea66227 Mon Sep 17 00:00:00 2001 From: Romain Tartiere Date: Sat, 3 Jul 2010 10:04:06 +0000 Subject: [PATCH] New API functions mad_application_read(), mad_application_write(). --- NEWS | 2 +- libfreefare/Makefile.am | 2 + libfreefare/freefare.h | 2 + libfreefare/mad.3 | 50 ++++++++++++++++- libfreefare/mad.c | 100 +++++++++++++++++++++++++++++++++ test/test_mifare_classic_mad.c | 46 +++++++++++++++ 6 files changed, 200 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 235d979..ec08539 100644 --- a/NEWS +++ b/NEWS @@ -10,4 +10,4 @@ Changes between 0.1.0 and x.x.x [xx XXX xxxx] *) New API functions mifare_classic_block_sector(), mifare_classic_sector_first_block(), mifare_classic_sector_block_count() and mifare_classic_sector_last_block(). - + *) New API functions mad_application_read(), mad_application_write(). diff --git a/libfreefare/Makefile.am b/libfreefare/Makefile.am index 8745438..1ceb52a 100644 --- a/libfreefare/Makefile.am +++ b/libfreefare/Makefile.am @@ -57,6 +57,8 @@ linkedman = \ mad.3 mad_get_aid.3 \ mad.3 mad_set_aid.3 \ mad.3 mad_free.3 \ + mad.3 mad_application_read.3 \ + mad.3 mad_application_write.3 \ mifare_application.3 mifare_application_alloc.3 \ mifare_application.3 mifare_application_free.3 \ mifare_application.3 mifare_application_find.3 \ diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index 479a27d..dd4f6e1 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -144,6 +144,8 @@ int mad_get_aid (Mad mad, MifareClassicSectorNumber sector, MadAid *aid); int mad_set_aid (Mad mad, MifareClassicSectorNumber sector, MadAid aid); bool mad_sector_reserved (MifareClassicSectorNumber sector); void mad_free (Mad mad); +ssize_t mad_application_read (MifareTag tag, Mad mad, MadAid aid, void *buf, size_t nbytes, MifareClassicKey key, MifareClassicKeyType key_type); +ssize_t mad_application_write (MifareTag tag, Mad mad, MadAid aid, const void *buf, size_t nbytes, MifareClassicKey key, MifareClassicKeyType key_type); MifareClassicSectorNumber *mifare_application_alloc (Mad mad, MadAid aid, size_t size); void mifare_application_free (Mad mad, MadAid aid); diff --git a/libfreefare/mad.3 b/libfreefare/mad.3 index 8713eb9..636e35e 100644 --- a/libfreefare/mad.3 +++ b/libfreefare/mad.3 @@ -34,7 +34,9 @@ .Nm mad_set_card_publisher_sector , .Nm mad_get_aid , .Nm mad_set_aid , -.Nm mad_free +.Nm mad_free , +.Nm mad_application_read , +.Nm mad_application_write .Nd "Mifare Application Directory (MAD) Manipulation Functions" .\" _ _ _ .\" | | (_) |__ _ __ __ _ _ __ _ _ @@ -72,6 +74,10 @@ Mifare card manipulation library (libfreefare, \-lfreefare) .Fn mad_set_aid "Mad mad" "MifareSectorNumber sector" "MadAid aid" .Ft void .Fn mad_free "Mad mad" +.Ft ssize_t +.Fn mad_application_read "MifareTag tag" "Mad mad" "MadAid aid" "void *buf" "size_t nbytes" "MifareClassicKey key" "MifareClassicKeyType key_type" +.Ft ssize_t +.Fn mad_application_write "MifareTag tag" "Mad mad" "MadAid aid" "const void *buf" size_t nbytes" "MifareClassicKey key" "MifareClassicKeyType key_type" .\" ____ _ _ _ .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ .\" | | | |/ _ \/ __|/ __| '__| | '_ \| __| |/ _ \| '_ \ @@ -141,6 +147,48 @@ functions. These functions fill-in or read the Application Identifier, .Vt aid for the given .Vt sector . +.Pp +The +.Fn mad_application_read +reads at most +.Vt nbytes +of the application identified by +.Vt aid +in the +.Vt mad +on the +.Vt tag +and copy them into +.Vt buf. +The function returns the amount of data it copied, or -1 on error. +.Pp +The +.Fn mad_application_write +functions writes at most +.Vt nbytes +of +.Vt buf +in the application identified by +.Vt aid +on the +.Vt mad +of the +.Vt tag +and returns the quantity of data written, or -1 on error. +.\" ___ _ _ _ _ _ +.\" |_ _|_ __ ___ _ __ | | ___ _ __ ___ ___ _ __ | |_ __ _| |_(_) ___ _ __ _ __ ___ | |_ ___ ___ +.\" | || '_ ` _ \| '_ \| |/ _ \ '_ ` _ \ / _ \ '_ \| __/ _` | __| |/ _ \| '_ \ | '_ \ / _ \| __/ _ \/ __| +.\" | || | | | | | |_) | | __/ | | | | | __/ | | | || (_| | |_| | (_) | | | | | | | | (_) | || __/\__ \ +.\" |___|_| |_| |_| .__/|_|\___|_| |_| |_|\___|_| |_|\__\__,_|\__|_|\___/|_| |_| |_| |_|\___/ \__\___||___/ +.\" |_| +.Sh IMPLEMENTATION NOTES +The +.Vt nbytes +argument of +.Fn mad_application_read +and +.Fn mad_application_write +does not need to be aligned on blocks not sectors. .\" ____ _ _ .\" | _ \ ___| |_ _ _ _ __ _ __ __ ____ _| |_ _ ___ ___ .\" | |_) / _ \ __| | | | '__| '_ \ \ \ / / _` | | | | |/ _ \/ __| diff --git a/libfreefare/mad.c b/libfreefare/mad.c index 666f6cf..7ed0740 100644 --- a/libfreefare/mad.c +++ b/libfreefare/mad.c @@ -46,6 +46,8 @@ #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; @@ -425,3 +427,101 @@ mad_free (Mad mad) { free (mad); } + +ssize_t +mad_application_read (MifareTag tag, Mad mad, MadAid aid, void *buf, size_t nbytes, MifareClassicKey key, MifareClassicKeyType key_type) +{ + ssize_t res = 0; + + MifareClassicSectorNumber *sectors = mifare_application_find (mad, aid); + MifareClassicSectorNumber *s = sectors; + + if (!sectors) + return errno = EBADF, -1; + + while (*s && nbytes && (res >= 0)) { + MifareClassicBlockNumber first_block = mifare_classic_sector_first_block (*s); + MifareClassicBlockNumber last_block = mifare_classic_sector_last_block (*s); + + MifareClassicBlockNumber b = first_block; + MifareClassicBlock block; + + if (mifare_classic_authenticate (tag, first_block, key, key_type) < 0) { + res = -1; + break; + } + + while ((b < last_block) && nbytes) { + size_t n = MIN (nbytes, 16); + + if (mifare_classic_read (tag, b, &block) < 0) { + res = -1; + break; + } + memcpy ((uint8_t *)buf + res, &block, n); + + nbytes -= n; + res += n; + + b++; + } + + s++; + } + + free (sectors); + return res; +} + +ssize_t +mad_application_write (MifareTag tag, Mad mad, MadAid aid, const void *buf, size_t nbytes, MifareClassicKey key, MifareClassicKeyType key_type) +{ + ssize_t res = 0; + + MifareClassicSectorNumber *sectors = mifare_application_find (mad, aid); + MifareClassicSectorNumber *s = sectors; + + if (!sectors) + return errno = EBADF, -1; + + while (*s && nbytes && (res >= 0)) { + MifareClassicBlockNumber first_block = mifare_classic_sector_first_block (*s); + MifareClassicBlockNumber last_block = mifare_classic_sector_last_block (*s); + + MifareClassicBlockNumber b = first_block; + MifareClassicBlock block; + + if (mifare_classic_authenticate (tag, first_block, key, key_type) < 0) { + res = -1; + break; + } + + while ((b < last_block) && nbytes) { + size_t n = MIN (nbytes, 16); + // Avoid overwriting existing data with uninitialized memory. + if (n < 16) { + if (mifare_classic_read (tag, b, &block) < 0) { + res = -1; + break; + } + } + + memcpy (&block, (uint8_t *)buf + res, n); + if (mifare_classic_write (tag, b, block) < 0) { + res = -1; + break; + } + + nbytes -= n; + res += n; + + b++; + } + + s++; + } + + free (sectors); + return res; + +} diff --git a/test/test_mifare_classic_mad.c b/test/test_mifare_classic_mad.c index c8bf6f3..bcc1de5 100644 --- a/test/test_mifare_classic_mad.c +++ b/test/test_mifare_classic_mad.c @@ -78,6 +78,36 @@ test_mifare_classic_mad (void) cut_assert_not_null (mad2, cut_message ("mad_read() failed")); cut_assert_equal_memory (mad, sizeof (mad), mad2, sizeof (mad2), cut_message ("Wrong MAD")); + const char application_data[] = "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " + "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " + "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " + "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " + "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " + "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> "; + + MadAid aid = { + .function_cluster_code = 0x01, + .application_code = 0x12 + }; + + // Write some data in the application + MifareClassicSectorNumber *sectors = mifare_application_alloc (mad, aid, sizeof (application_data)); + cut_assert_not_null (sectors, cut_message ("mifare_application_alloc() failed")); + free (sectors); + + res = mad_write (tag, mad, key_b_sector_00, NULL); + cut_assert_equal_int (0, res, cut_message ("mad_write() failed")); + + ssize_t s = mad_application_write (tag, mad, aid, &application_data, sizeof (application_data), key_a_transport, MFC_KEY_A); + cut_assert_equal_int (sizeof (application_data), s, cut_message ("mad_application_write() failed")); + + char read_buf[500]; + + // Read it again + s = mad_application_read (tag, mad, aid, read_buf, sizeof (application_data), key_a_transport, MFC_KEY_A); + cut_assert_equal_int (sizeof (application_data), s, cut_message ("mad_application_read() failed")); + cut_assert_equal_memory (application_data, sizeof (application_data), read_buf, s, cut_message ("Wrong application data")); + mad_free (mad); mad_free (mad2); @@ -161,6 +191,22 @@ test_mifare_classic_mad (void) cut_assert_not_null (mad2, cut_message ("mad_read() failed")); cut_assert_equal_memory (mad, sizeof (mad), mad2, sizeof (mad2), cut_message ("Wrong MAD")); + // Write some data in the application + sectors = mifare_application_alloc (mad, aid, sizeof (application_data)); + cut_assert_not_null (sectors, cut_message ("mifare_application_alloc() failed")); + free (sectors); + + res = mad_write (tag, mad, key_b_sector_00, key_b_sector_10); + cut_assert_equal_int (0, res, cut_message ("mad_write() failed")); + + s = mad_application_write (tag, mad, aid, &application_data, sizeof (application_data), key_a_transport, MFC_KEY_A); + cut_assert_equal_int (sizeof (application_data), s, cut_message ("mad_application_write() failed")); + + // Read it again + s = mad_application_read (tag, mad, aid, read_buf, sizeof (application_data), key_a_transport, MFC_KEY_A); + cut_assert_equal_int (sizeof (application_data), s, cut_message ("mad_application_read() failed")); + cut_assert_equal_memory (application_data, sizeof (application_data), read_buf, s, cut_message ("Wrong application data")); + mad_free (mad); mad_free (mad2);