From a643e9149db9d957c401c2e55e0c4e00f64889a5 Mon Sep 17 00:00:00 2001 From: Romain Tartiere Date: Sat, 20 Nov 2010 14:10:27 +0000 Subject: [PATCH] Add an offset parameter to mifare_cryto_preprocess_data() Some cryptographic operations are performed on the whole data frame and not only the payload with Mifare DESFire EV1. The solution for now is not perfect, (one new macro wrapping another big macro) but makes the code a bit easier to read, and with the MIFARE_DESFIRE macro rewriting as a function (at some point in the future), the whole should be bearable :-) --- libfreefare/freefare_internal.h | 2 +- libfreefare/mifare_desfire.c | 66 +++++++++++------------ libfreefare/mifare_desfire_authenticate.c | 18 ++++--- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h index 61192da..ce6b167 100644 --- a/libfreefare/freefare_internal.h +++ b/libfreefare/freefare_internal.h @@ -116,7 +116,7 @@ typedef enum { MD_RECEIVE } MifareDirection; -void *mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int communication_settings); +void *mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t offset, 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 *ivect, uint8_t *data, size_t data_size, MifareDirection direction, int mac); void rol (uint8_t *data, const size_t len); diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index ed3b243..82c7361 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -155,14 +155,16 @@ static uint8_t __res[MAX_FRAME_SIZE]; * response is copied at the beginning to match the PICC documentation. */ #define DESFIRE_TRANSCEIVE(tag, msg, res) \ + DESFIRE_TRANSCEIVE2 (tag, msg, __##msg##_n, res) +#define DESFIRE_TRANSCEIVE2(tag, msg, msg_len, res) \ do { \ size_t __len = 5; \ errno = 0; \ __msg[1] = msg[0]; \ - if (__##msg##_n > 1) { \ - __len += __##msg##_n; \ - __msg[4] = __##msg##_n - 1; \ - memcpy (__msg + 5, msg + 1, __##msg##_n - 1); \ + if (msg_len > 1) { \ + __len += msg_len; \ + __msg[4] = msg_len - 1; \ + memcpy (__msg + 5, msg + 1, msg_len - 1); \ } \ __msg[__len-1] = 0x00; \ MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \ @@ -999,24 +1001,25 @@ write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_ ASSERT_MIFARE_DESFIRE (tag); ASSERT_CS (cs); - BUFFER_INIT (cmd, MAX_FRAME_SIZE); + BUFFER_INIT (cmd, 8 + length); BUFFER_INIT (res, 1); BUFFER_APPEND (cmd, command); BUFFER_APPEND (cmd, file_no); BUFFER_APPEND_LE (cmd, offset, 3, sizeof (off_t)); BUFFER_APPEND_LE (cmd, length, 3, sizeof (size_t)); + BUFFER_APPEND_BYTES (cmd, data, length); - p = mifare_cryto_preprocess_data (tag, data, &length, cs); + p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 8, cs); - bytes_left = FRAME_PAYLOAD_SIZE - 8; + BUFFER_INIT(d, FRAME_PAYLOAD_SIZE); + bytes_left = FRAME_PAYLOAD_SIZE; - while (bytes_send < length) { - size_t frame_bytes = MIN(bytes_left, length - bytes_send); + while (bytes_send < __cmd_n) { + size_t frame_bytes = MIN(bytes_left, __cmd_n - bytes_send); + BUFFER_APPEND_BYTES (d, (uint8_t *) p + bytes_send, frame_bytes); - BUFFER_APPEND_BYTES (cmd, (uint8_t *)p + bytes_send, frame_bytes); - - DESFIRE_TRANSCEIVE (tag, cmd, res); + DESFIRE_TRANSCEIVE (tag, d, res); bytes_send += frame_bytes; @@ -1024,12 +1027,15 @@ write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_ break; // PICC returned 0xAF and expects more data - BUFFER_CLEAR (cmd); - BUFFER_APPEND (cmd, 0xAF); + BUFFER_CLEAR (d); + BUFFER_APPEND (d, 0xAF); bytes_left = FRAME_PAYLOAD_SIZE - 1; } - if (0x00 != res[__res_n-1]) { + if (0x00 == res[__res_n-1]) { + // Remove header length + bytes_send -= 8; + } else { // 0xAF (additionnal Frame) failure can happen here (wrong crypto method). MIFARE_DESFIRE (tag)->last_picc_error = res[__res_n-1]; bytes_send = -1; @@ -1109,16 +1115,12 @@ mifare_desfire_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs BUFFER_INIT (cmd, 10); BUFFER_INIT (res, 1); - BUFFER_INIT (data, 4); - BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t)); - BUFFER_APPEND (cmd, 0x0C); BUFFER_APPEND (cmd, file_no); - size_t n = 4; - void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); - BUFFER_APPEND_BYTES (cmd, d, n); + BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs); - DESFIRE_TRANSCEIVE (tag, cmd, res); + DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); cached_file_settings_current[file_no] = false; @@ -1140,16 +1142,12 @@ mifare_desfire_debit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs) BUFFER_INIT (cmd, 10); BUFFER_INIT (res, 1); - BUFFER_INIT (data, 4); - BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t)); - BUFFER_APPEND (cmd, 0xDC); BUFFER_APPEND (cmd, file_no); - size_t n = 4; - void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); - BUFFER_APPEND_BYTES (cmd, d, n); + BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs); - DESFIRE_TRANSCEIVE (tag, cmd, res); + DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); cached_file_settings_current[file_no] = false; @@ -1171,16 +1169,12 @@ mifare_desfire_limited_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount BUFFER_INIT (cmd, 10); BUFFER_INIT (res, 1); - BUFFER_INIT (data, 4); - BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t)); - BUFFER_APPEND (cmd, 0x1C); BUFFER_APPEND (cmd, file_no); - size_t n = 4; - void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); - BUFFER_APPEND_BYTES (cmd, d, n); + BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs); - DESFIRE_TRANSCEIVE (tag, cmd, res); + DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); cached_file_settings_current[file_no] = false; diff --git a/libfreefare/mifare_desfire_authenticate.c b/libfreefare/mifare_desfire_authenticate.c index f9d934e..2cdba38 100644 --- a/libfreefare/mifare_desfire_authenticate.c +++ b/libfreefare/mifare_desfire_authenticate.c @@ -131,11 +131,15 @@ assert_crypto_buffer_size (MifareTag tag, size_t nbytes) } void * -mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int communication_settings) +mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, off_t offset, int communication_settings) { void *res; uint8_t mac[4]; size_t edl, mdl; + MifareDESFireKey key = MIFARE_DESFIRE (tag)->session_key; + + if (!key) + return data; switch (communication_settings) { case 0: @@ -143,7 +147,7 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com res = data; break; case 1: - edl = padded_data_length (*nbytes, key_block_size (MIFARE_DESFIRE (tag)->session_key)); + edl = padded_data_length (*nbytes - offset, key_block_size (MIFARE_DESFIRE (tag)->session_key)) + offset; if (!(res = assert_crypto_buffer_size (tag, edl))) abort(); @@ -152,11 +156,11 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com // ... and 0 padding bzero ((uint8_t *)res + *nbytes, edl - *nbytes); - mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, res, edl, MD_SEND, 1); + mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, (uint8_t *) res + offset, edl - offset, MD_SEND, 1); memcpy (mac, (uint8_t *)res + edl - 8, 4); - mdl = maced_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes); + mdl = maced_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes - offset) + offset; if (!(res = assert_crypto_buffer_size (tag, mdl))) abort(); @@ -167,20 +171,20 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com break; case 3: - edl = enciphered_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes); + edl = enciphered_data_length (MIFARE_DESFIRE (tag)->session_key, *nbytes - offset) + offset; if (!(res = assert_crypto_buffer_size (tag, edl))) abort(); // Fill in the crypto buffer with data ... memcpy (res, data, *nbytes); // ... CRC ... - iso14443a_crc_append (res, *nbytes); + iso14443a_crc_append ((uint8_t *)res + offset, *nbytes - offset); // ... and 0 padding bzero ((uint8_t *)(res) + *nbytes + 2, edl - *nbytes - 2); *nbytes = edl; - mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, res, *nbytes, MD_SEND, 0); + mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, MIFARE_DESFIRE (tag)->ivect, (uint8_t *) res + offset, *nbytes - offset, MD_SEND, 0); break; default: