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 :-)
This commit is contained in:
Romain Tartiere 2010-11-20 14:10:27 +00:00
parent 16ae154b42
commit a643e9149d
3 changed files with 42 additions and 44 deletions

View file

@ -116,7 +116,7 @@ typedef enum {
MD_RECEIVE MD_RECEIVE
} MifareDirection; } 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_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 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); void rol (uint8_t *data, const size_t len);

View file

@ -155,14 +155,16 @@ static uint8_t __res[MAX_FRAME_SIZE];
* response is copied at the beginning to match the PICC documentation. * response is copied at the beginning to match the PICC documentation.
*/ */
#define DESFIRE_TRANSCEIVE(tag, msg, res) \ #define DESFIRE_TRANSCEIVE(tag, msg, res) \
DESFIRE_TRANSCEIVE2 (tag, msg, __##msg##_n, res)
#define DESFIRE_TRANSCEIVE2(tag, msg, msg_len, res) \
do { \ do { \
size_t __len = 5; \ size_t __len = 5; \
errno = 0; \ errno = 0; \
__msg[1] = msg[0]; \ __msg[1] = msg[0]; \
if (__##msg##_n > 1) { \ if (msg_len > 1) { \
__len += __##msg##_n; \ __len += msg_len; \
__msg[4] = __##msg##_n - 1; \ __msg[4] = msg_len - 1; \
memcpy (__msg + 5, msg + 1, __##msg##_n - 1); \ memcpy (__msg + 5, msg + 1, msg_len - 1); \
} \ } \
__msg[__len-1] = 0x00; \ __msg[__len-1] = 0x00; \
MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \ 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_MIFARE_DESFIRE (tag);
ASSERT_CS (cs); ASSERT_CS (cs);
BUFFER_INIT (cmd, MAX_FRAME_SIZE); BUFFER_INIT (cmd, 8 + length);
BUFFER_INIT (res, 1); BUFFER_INIT (res, 1);
BUFFER_APPEND (cmd, command); BUFFER_APPEND (cmd, command);
BUFFER_APPEND (cmd, file_no); BUFFER_APPEND (cmd, file_no);
BUFFER_APPEND_LE (cmd, offset, 3, sizeof (off_t)); BUFFER_APPEND_LE (cmd, offset, 3, sizeof (off_t));
BUFFER_APPEND_LE (cmd, length, 3, sizeof (size_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) { while (bytes_send < __cmd_n) {
size_t frame_bytes = MIN(bytes_left, length - bytes_send); 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, d, res);
DESFIRE_TRANSCEIVE (tag, cmd, res);
bytes_send += frame_bytes; bytes_send += frame_bytes;
@ -1024,12 +1027,15 @@ write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_
break; break;
// PICC returned 0xAF and expects more data // PICC returned 0xAF and expects more data
BUFFER_CLEAR (cmd); BUFFER_CLEAR (d);
BUFFER_APPEND (cmd, 0xAF); BUFFER_APPEND (d, 0xAF);
bytes_left = FRAME_PAYLOAD_SIZE - 1; 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). // 0xAF (additionnal Frame) failure can happen here (wrong crypto method).
MIFARE_DESFIRE (tag)->last_picc_error = res[__res_n-1]; MIFARE_DESFIRE (tag)->last_picc_error = res[__res_n-1];
bytes_send = -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 (cmd, 10);
BUFFER_INIT (res, 1); BUFFER_INIT (res, 1);
BUFFER_INIT (data, 4);
BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t));
BUFFER_APPEND (cmd, 0x0C); BUFFER_APPEND (cmd, 0x0C);
BUFFER_APPEND (cmd, file_no); BUFFER_APPEND (cmd, file_no);
size_t n = 4; BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t));
void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs);
BUFFER_APPEND_BYTES (cmd, d, n);
DESFIRE_TRANSCEIVE (tag, cmd, res); DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
cached_file_settings_current[file_no] = false; 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 (cmd, 10);
BUFFER_INIT (res, 1); BUFFER_INIT (res, 1);
BUFFER_INIT (data, 4);
BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t));
BUFFER_APPEND (cmd, 0xDC); BUFFER_APPEND (cmd, 0xDC);
BUFFER_APPEND (cmd, file_no); BUFFER_APPEND (cmd, file_no);
size_t n = 4; BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t));
void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs);
BUFFER_APPEND_BYTES (cmd, d, n);
DESFIRE_TRANSCEIVE (tag, cmd, res); DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
cached_file_settings_current[file_no] = false; 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 (cmd, 10);
BUFFER_INIT (res, 1); BUFFER_INIT (res, 1);
BUFFER_INIT (data, 4);
BUFFER_APPEND_LE (data, amount, 4, sizeof (int32_t));
BUFFER_APPEND (cmd, 0x1C); BUFFER_APPEND (cmd, 0x1C);
BUFFER_APPEND (cmd, file_no); BUFFER_APPEND (cmd, file_no);
size_t n = 4; BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t));
void *d = mifare_cryto_preprocess_data (tag, data, &n, cs); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs);
BUFFER_APPEND_BYTES (cmd, d, n);
DESFIRE_TRANSCEIVE (tag, cmd, res); DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res);
cached_file_settings_current[file_no] = false; cached_file_settings_current[file_no] = false;

View file

@ -131,11 +131,15 @@ assert_crypto_buffer_size (MifareTag tag, size_t nbytes)
} }
void * 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; void *res;
uint8_t mac[4]; uint8_t mac[4];
size_t edl, mdl; size_t edl, mdl;
MifareDESFireKey key = MIFARE_DESFIRE (tag)->session_key;
if (!key)
return data;
switch (communication_settings) { switch (communication_settings) {
case 0: case 0:
@ -143,7 +147,7 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com
res = data; res = data;
break; break;
case 1: 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))) if (!(res = assert_crypto_buffer_size (tag, edl)))
abort(); abort();
@ -152,11 +156,11 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com
// ... and 0 padding // ... and 0 padding
bzero ((uint8_t *)res + *nbytes, edl - *nbytes); 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); 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))) if (!(res = assert_crypto_buffer_size (tag, mdl)))
abort(); abort();
@ -167,20 +171,20 @@ mifare_cryto_preprocess_data (MifareTag tag, void *data, size_t *nbytes, int com
break; break;
case 3: 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))) if (!(res = assert_crypto_buffer_size (tag, edl)))
abort(); abort();
// Fill in the crypto buffer with data ... // Fill in the crypto buffer with data ...
memcpy (res, data, *nbytes); memcpy (res, data, *nbytes);
// ... CRC ... // ... CRC ...
iso14443a_crc_append (res, *nbytes); iso14443a_crc_append ((uint8_t *)res + offset, *nbytes - offset);
// ... and 0 padding // ... and 0 padding
bzero ((uint8_t *)(res) + *nbytes + 2, edl - *nbytes - 2); bzero ((uint8_t *)(res) + *nbytes + 2, edl - *nbytes - 2);
*nbytes = edl; *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; break;
default: default: