diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h
index b60dee2..882d6e5 100644
--- a/libfreefare/freefare.h
+++ b/libfreefare/freefare.h
@@ -304,6 +304,7 @@ int mifare_desfire_connect (MifareTag tag);
int mifare_desfire_disconnect (MifareTag tag);
int mifare_desfire_authenticate (MifareTag tag, uint8_t key_no, MifareDESFireKey key);
+int mifare_desfire_authenticate_iso (MifareTag tag, uint8_t key_no, MifareDESFireKey key);
int mifare_desfire_authenticate_aes (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);
@@ -353,6 +354,8 @@ 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]);
+MifareDESFireKey mifare_desfire_3k3des_key_new (uint8_t value[24]);
+MifareDESFireKey mifare_desfire_3k3des_key_new_with_version (uint8_t value[24]);
MifareDESFireKey mifare_desfire_aes_key_new (uint8_t value[16]);
MifareDESFireKey mifare_desfire_aes_key_new_with_version (uint8_t value[16], uint8_t version);
uint8_t mifare_desfire_key_get_version (MifareDESFireKey key);
diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h
index 6d70522..139d476 100644
--- a/libfreefare/freefare_internal.h
+++ b/libfreefare/freefare_internal.h
@@ -201,16 +201,18 @@ struct mifare_desfire_aid {
};
struct mifare_desfire_key {
- uint8_t data[16];
+ uint8_t data[24];
enum {
T_DES,
T_3DES,
+ T_3K3DES,
T_AES
} type;
DES_key_schedule ks1;
DES_key_schedule ks2;
- uint8_t cmac_sk1[16];
- uint8_t cmac_sk2[16];
+ DES_key_schedule ks3;
+ uint8_t cmac_sk1[24];
+ uint8_t cmac_sk2[24];
uint8_t aes_version;
};
diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c
index c58464d..477a24d 100644
--- a/libfreefare/mifare_desfire.c
+++ b/libfreefare/mifare_desfire.c
@@ -399,6 +399,7 @@ authenticate (MifareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key)
case T_DES:
case T_3DES:
break;
+ case T_3K3DES:
case T_AES:
cmac_generate_subkeys (MIFARE_DESFIRE (tag)->session_key);
break;
@@ -413,6 +414,12 @@ mifare_desfire_authenticate (MifareTag tag, uint8_t key_no, MifareDESFireKey key
return authenticate (tag, 0x0A, key_no, key);
}
+int
+mifare_desfire_authenticate_iso (MifareTag tag, uint8_t key_no, MifareDESFireKey key)
+{
+ return authenticate (tag, 0x1A, key_no, key);
+}
+
int
mifare_desfire_authenticate_aes (MifareTag tag, uint8_t key_no, MifareDESFireKey key)
{
@@ -437,7 +444,7 @@ mifare_desfire_change_key_settings (MifareTag tag, uint8_t settings)
DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
ssize_t n = __res_n;
- p = mifare_cryto_postprocess_data (tag, res, &n, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
+ p = mifare_cryto_postprocess_data (tag, res, &n, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_COMMAND | MAC_VERIFY);
return 0;
}
@@ -489,6 +496,9 @@ mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_k
case T_DES:
case T_3DES:
break;
+ case T_3K3DES:
+ key_no |= 0x40;
+ break;
case T_AES:
key_no |= 0x80;
break;
@@ -505,6 +515,9 @@ mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_k
case T_AES:
new_key_length = 16;
break;
+ case T_3K3DES:
+ new_key_length = 24;
+ break;
}
memcpy (cmd + __cmd_n, new_key->data, new_key_length);
@@ -531,6 +544,7 @@ mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_k
iso14443a_crc (new_key->data, new_key_length, cmd + __cmd_n);
__cmd_n += 2;
break;
+ case T_3K3DES:
case T_AES:
desfire_crc32_append (cmd, __cmd_n);
__cmd_n += 4;
@@ -546,6 +560,7 @@ mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_k
iso14443a_crc_append (cmd + 2 , __cmd_n - 2);
__cmd_n += 2;
break;
+ case T_3K3DES:
case T_AES:
desfire_crc32_append (cmd, __cmd_n);
__cmd_n += 4;
@@ -594,7 +609,7 @@ mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *version)
DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
ssize_t sn = __res_n;
- p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
+ p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
*version = p[0];
@@ -625,7 +640,7 @@ create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings1, uint
DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
ssize_t sn = __res_n;
- mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
+ mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
return 0;
}
@@ -699,7 +714,7 @@ mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], siz
}
ssize_t sn = __res_n;
- p = mifare_cryto_postprocess_data (tag, buffer, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY);
+ p = mifare_cryto_postprocess_data (tag, buffer, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
*count = (sn - 1)/3;
@@ -1208,6 +1223,7 @@ read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t
case T_DES:
case T_3DES:
break;
+ case T_3K3DES:
case T_AES:
cs = MDCM_PLAIN;
break;
diff --git a/libfreefare/mifare_desfire_authenticate.c b/libfreefare/mifare_desfire_authenticate.c
index a1230fa..4b72485 100644
--- a/libfreefare/mifare_desfire_authenticate.c
+++ b/libfreefare/mifare_desfire_authenticate.c
@@ -203,6 +203,7 @@ key_block_size (const MifareDESFireKey key)
switch (key->type) {
case T_DES:
case T_3DES:
+ case T_3K3DES:
block_size = 8;
break;
case T_AES:
@@ -226,6 +227,7 @@ key_macing_length (const MifareDESFireKey key)
case T_3DES:
mac_length = MAC_LENGTH;
break;
+ case T_3K3DES:
case T_AES:
mac_length = CMAC_LENGTH;
break;
@@ -267,6 +269,7 @@ enciphered_data_length (const MifareDESFireKey key, const size_t nbytes, int com
case T_3DES:
crc_length = 2;
break;
+ case T_3K3DES:
case T_AES:
crc_length = 4;
break;
@@ -331,6 +334,8 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
case T_3DES:
if (!(communication_settings & MAC_COMMAND))
break;
+
+ /* pass through */
edl = padded_data_length (*nbytes - offset, key_block_size (MIFARE_DESFIRE (tag)->session_key)) + offset;
if (!(res = assert_crypto_buffer_size (tag, edl)))
abort();
@@ -347,6 +352,8 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
// Copy again provided data (was overwritten by mifare_cbc_des)
memcpy (res, data, *nbytes);
+ if (!(communication_settings & MAC_COMMAND))
+ break;
// Append MAC
mdl = maced_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes - offset) + offset;
if (!(res = assert_crypto_buffer_size (tag, mdl)))
@@ -356,6 +363,7 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
*nbytes += 4;
break;
+ case T_3K3DES:
case T_AES:
if (!(communication_settings & CMAC_COMMAND))
break;
@@ -393,6 +401,7 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
switch (key->type) {
case T_DES:
case T_3DES:
+ case T_3K3DES:
if (!(communication_settings & ENC_COMMAND))
break;
edl = enciphered_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes - offset, communication_settings) + offset;
@@ -409,6 +418,10 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
iso14443a_crc_append ((uint8_t *)res + offset, *nbytes - offset);
*nbytes += 2;
break;
+ case T_3K3DES:
+ desfire_crc32_append ((uint8_t *)res, *nbytes);
+ *nbytes += 4;
+ break;
case T_AES:
// Never reached.
abort ();
@@ -420,7 +433,7 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t o
*nbytes = edl;
- mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, (uint8_t *) res + offset, *nbytes - offset, MD_SEND, 0);
+ mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, (uint8_t *) res + offset, *nbytes - offset, MD_SEND, (key->type == T_3K3DES) ? 1 : 0);
break;
case T_AES:
@@ -504,8 +517,8 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
warnx ("MACing not verified");
#if WITH_DEBUG
- hexdump ((uint8_t *)data + *nbytes - 1, 4, "Expect ", 0);
- hexdump ((uint8_t *)edata + edl - 8, 4, "Actual ", 0);
+ hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0);
+ hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0);
abort ();
#endif
*nbytes = -1;
@@ -513,6 +526,7 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
}
}
break;
+ case T_3K3DES:
case T_AES:
if (!(communication_settings & CMAC_COMMAND))
break;
@@ -594,6 +608,7 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
}
break;
+ case T_3K3DES:
case T_AES:
(*nbytes)--;
mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, res, *nbytes, MD_RECEIVE, 0);
@@ -670,6 +685,17 @@ mifare_des (MifareDESFireKey key, uint8_t *data, uint8_t *ivect, MifareDirection
DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks1), DES_DECRYPT);
}
break;
+ case T_3K3DES:
+ 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->ks3), DES_ENCRYPT);
+ } else {
+ DES_ecb_encrypt ((DES_cblock *) data, (DES_cblock *) edata, &(key->ks3), 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);
+ }
+ break;
case T_AES:
if (mac) {
AES_KEY k;
@@ -702,6 +728,8 @@ mifare_cbc_des (MifareDESFireKey key, uint8_t *ivect, uint8_t *data, size_t data
case T_DES:
case T_3DES:
memset (ivect, 0, MAX_CRYPTO_BLOCK_SIZE);
+ /* pass-through */
+ case T_3K3DES:
block_size = 8;
break;
case T_AES:
diff --git a/libfreefare/mifare_desfire_key.c b/libfreefare/mifare_desfire_key.c
index 8a9836f..efa63c1 100644
--- a/libfreefare/mifare_desfire_key.c
+++ b/libfreefare/mifare_desfire_key.c
@@ -32,6 +32,9 @@ update_key_schedules (MifareDESFireKey key)
{
DES_set_key ((DES_cblock *)key->data, &(key->ks1));
DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2));
+ if (T_3K3DES == key->type) {
+ DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3));
+ }
}
MifareDESFireKey
@@ -50,10 +53,10 @@ mifare_desfire_des_key_new_with_version (uint8_t value[8])
MifareDESFireKey key;
if ((key = malloc (sizeof (struct mifare_desfire_key)))) {
+ key->type = T_DES;
memcpy (key->data, value, 8);
memcpy (key->data+8, value, 8);
update_key_schedules (key);
- key->type = T_DES;
}
return key;
}
@@ -76,9 +79,32 @@ mifare_desfire_3des_key_new_with_version (uint8_t value[16])
MifareDESFireKey key;
if ((key = malloc (sizeof (struct mifare_desfire_key)))) {
+ key->type = T_3DES;
memcpy (key->data, value, 16);
update_key_schedules (key);
- key->type = T_3DES;
+ }
+ return key;
+}
+
+MifareDESFireKey
+mifare_desfire_3k3des_key_new (uint8_t value[24])
+{
+ uint8_t data[24];
+ memcpy (data, value, 24);
+ for (int n=0; n < 8; n++)
+ data[n] &= 0xfe;
+ return mifare_desfire_3k3des_key_new_with_version (data);
+}
+
+MifareDESFireKey
+mifare_desfire_3k3des_key_new_with_version (uint8_t value[24])
+{
+ MifareDESFireKey key;
+
+ if ((key = malloc (sizeof (struct mifare_desfire_key)))) {
+ key->type = T_3K3DES;
+ memcpy (key->data, value, 24);
+ update_key_schedules (key);
}
return key;
}
@@ -136,7 +162,7 @@ mifare_desfire_session_key_new (uint8_t rnda[8], uint8_t rndb[8], MifareDESFireK
{
MifareDESFireKey key = NULL;
- uint8_t buffer[16];
+ uint8_t buffer[24];
switch (authentication_key->type) {
case T_DES:
@@ -151,6 +177,15 @@ mifare_desfire_session_key_new (uint8_t rnda[8], uint8_t rndb[8], MifareDESFireK
memcpy (buffer+12, rndb+4, 4);
key = mifare_desfire_3des_key_new_with_version (buffer);
break;
+ case T_3K3DES:
+ memcpy (buffer, rnda, 4);
+ memcpy (buffer+4, rndb, 4);
+ memcpy (buffer+8, rnda+6, 4);
+ memcpy (buffer+12, rndb+6, 4);
+ memcpy (buffer+16, rnda+12, 4);
+ memcpy (buffer+20, rndb+12, 4);
+ key = mifare_desfire_3k3des_key_new (buffer);
+ break;
case T_AES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
diff --git a/test/Makefile.am b/test/Makefile.am
index 586c3ba..20b038f 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -63,6 +63,7 @@ test_mifare_desfire_des_la_SOURCES = test_mifare_desfire_des.c
test_mifare_desfire_des_la_LIBADD = $(top_builddir)/libfreefare/libfreefare.la
test_mifare_desfire_ev1_la_SOURCES = test_mifare_desfire_ev1.c \
+ test_mifare_desfire_ev1_3k3des.c \
test_mifare_desfire_ev1_aes.c \
mifare_desfire_ev1_fixture.c \
mifare_desfire_ev1_fixture.h
diff --git a/test/common/mifare_desfire_auto_authenticate.c b/test/common/mifare_desfire_auto_authenticate.c
index 8aa7f00..7c38bad 100644
--- a/test/common/mifare_desfire_auto_authenticate.c
+++ b/test/common/mifare_desfire_auto_authenticate.c
@@ -27,6 +27,8 @@ 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', '!' };
uint8_t key_data_aes[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+uint8_t key_data_3k3des[24] = { 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t key_data_aes_version = 0x42;
@@ -53,6 +55,9 @@ mifare_desfire_auto_authenticate (MifareTag tag, uint8_t key_no)
case 0xC7:
key = mifare_desfire_3des_key_new_with_version (key_data_3des);
break;
+ case 0x55:
+ key = mifare_desfire_3k3des_key_new_with_version (key_data_3k3des);
+ break;
default:
cut_fail ("Unknown master key.");
}
@@ -66,8 +71,12 @@ mifare_desfire_auto_authenticate (MifareTag tag, uint8_t key_no)
case 0xC7:
res = mifare_desfire_authenticate (tag, key_no, key);
break;
+ case 0x55:
+ res = mifare_desfire_authenticate_iso (tag, key_no, key);
+ break;
case 0x42:
res = mifare_desfire_authenticate_aes (tag, key_no, key);
+ break;
}
cut_assert_equal_int (0, res, cut_message ("mifare_desfire_authenticate()"));
diff --git a/test/common/mifare_desfire_auto_authenticate.h b/test/common/mifare_desfire_auto_authenticate.h
index fa0c1c3..4240420 100644
--- a/test/common/mifare_desfire_auto_authenticate.h
+++ b/test/common/mifare_desfire_auto_authenticate.h
@@ -24,6 +24,7 @@ extern uint8_t key_data_null[8];
extern uint8_t key_data_des[8];
extern uint8_t key_data_3des[16];
extern uint8_t key_data_aes[16];
+extern uint8_t key_data_3k3des[24];
extern const uint8_t key_data_aes_version;
void mifare_desfire_auto_authenticate (MifareTag tag, uint8_t key_no);
diff --git a/test/test_mifare_desfire_ev1_3k3des.c b/test/test_mifare_desfire_ev1_3k3des.c
new file mode 100644
index 0000000..2ae021f
--- /dev/null
+++ b/test/test_mifare_desfire_ev1_3k3des.c
@@ -0,0 +1,831 @@
+/*-
+ * Copyright (C) 2010, Romain Tartiere.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see
+ *
+ * $Id$
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include "freefare_internal.h"
+
+#include "mifare_desfire_ev1_fixture.h"
+#include "common/mifare_desfire_auto_authenticate.h"
+
+#define cut_assert_success(last_command) \
+ do { \
+ if ((res < 0) || (mifare_desfire_last_picc_error (tag) != OPERATION_OK)) { \
+ cut_fail ("%s returned %d, error: %s, errno: %s\n", last_command, res, mifare_desfire_error_lookup (mifare_desfire_last_picc_error (tag)), strerror (errno)); \
+ } \
+ } while (0)
+
+void
+test_mifare_desfire_ev1_3k3des (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()");
+
+ mifare_desfire_auto_authenticate (tag, 0);
+
+ /*
+ * 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()");
+ res = mifare_desfire_change_key_settings (tag, 0xF);
+ cut_assert_success ("mifare_desfire_change_key_settings()");
+
+ /* Change master key to AES */
+ MifareDESFireKey key = mifare_desfire_3k3des_key_new_with_version (key_data_3k3des);
+ mifare_desfire_change_key (tag, 0, key, NULL);
+ cut_assert_success ("mifare_desfire_change_key()");
+
+ res = mifare_desfire_authenticate_iso (tag, 0, key);
+ cut_assert_success ("mifare_desfire_authenticate_iso()");
+ 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()");
+
+ key = mifare_desfire_3k3des_key_new_with_version (key_data_3k3des);
+ res = mifare_desfire_authenticate_iso (tag, 0, key);
+ cut_assert_success ("mifare_desfire_authenticate_iso()");
+ mifare_desfire_key_free (key);
+
+ uint8_t key_version;
+ res = mifare_desfire_get_key_version (tag, 0, &key_version);
+ cut_assert_success ("mifare_desfire_get_key_version()");
+ cut_assert_equal_int (0x55, 0x55, cut_message ("Wrong key_version value."));
+
+ uint32_t size;
+ res = mifare_desfire_free_mem (tag, &size);
+ cut_assert_success ("mifare_desfire_free_mem()");
+
+ MifareDESFireAID aid_a = mifare_desfire_aid_new (0x00AAAAAA);
+ //cut_assert_not_null (aid_a, cut_message ("Cannot allocate AID"));
+ res = mifare_desfire_create_application (tag, aid_a, 0xFF, 0);
+ cut_assert_success ("mifare_desfire_create_application()");
+
+ MifareDESFireAID aid_b = mifare_desfire_aid_new (0x00BBBBBB);
+ cut_assert_not_null (aid_b, cut_message ("Cannot allocate AID"));
+ res = mifare_desfire_create_application (tag, aid_b, 0xEF, 0x40 | 6);
+ cut_assert_success ("mifare_desfire_create_application()");
+
+ MifareDESFireAID aid_c = mifare_desfire_aid_new (0x00CCCCCC);
+ cut_assert_not_null (aid_c, cut_message ("Cannot allocate AID"));
+ res = mifare_desfire_create_application (tag, aid_c, 0xC2, 0x40 | 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_last_picc_error (tag), 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