Merge CRC location / verification in mifare_cryto_postprocess_data().

Fix issue 52.
This commit is contained in:
Romain Tartiere 2011-04-24 11:43:07 +00:00
parent de64cce14c
commit 35b87d4acd

View file

@ -524,9 +524,32 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
case MDCM_ENCIPHERED: case MDCM_ENCIPHERED:
(*nbytes)--; (*nbytes)--;
bool verified = false; bool verified = false;
int crc_pos;
int end_crc_pos; int end_crc_pos;
switch (MIFARE_DESFIRE (tag)->authentication_scheme) { uint8_t x;
case AS_LEGACY:
/*
* AS_LEGACY:
* ,-----------------+-------------------------------+--------+
* \ BLOCK n-1 | BLOCK n | STATUS |
* / PAYLOAD | CRC0 | CRC1 | 0x80? | 0x000000000000 | 0x9100 |
* `-----------------+-------------------------------+--------+
*
* <------------ DATA ------------>
* FRAME = PAYLOAD + CRC(PAYLOAD) + PADDING
*
* AS_NEW:
* ,-------------------------------+-----------------------------------------------+--------+
* \ BLOCK n-1 | BLOCK n | STATUS |
* / PAYLOAD | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x0000000000000000000000000000 | 0x9100 |
* `-------------------------------+-----------------------------------------------+--------+
* <----------------------------------- DATA ------------------------------------->|
*
* <----------------- DATA ---------------->
* FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS
* `------------------'
*/
mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER); mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER);
/* /*
@ -534,72 +557,41 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
* can't start by the end because the CRC is supposed to be 0 when * 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. * verified, and accumulating 0's in it should not change it.
*/ */
end_crc_pos = *nbytes - 7; // The CRC can be over two blocks switch (MIFARE_DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
do { crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
uint16_t crc; break;
iso14443a_crc (res, end_crc_pos, (uint8_t *)&crc); case AS_NEW:
if (!crc) { /* Move status between payload and CRC */
verified = true; res = assert_crypto_buffer_size (tag, (*nbytes) + 1);
for (int n = end_crc_pos; n < *nbytes - 1; n++) { memcpy (res, data, *nbytes);
uint8_t byte = ((uint8_t *)res)[n];
if (!( (0x00 == byte) || ((0x80 == byte) && (n == end_crc_pos)) )) crc_pos = (*nbytes) - 16 - 3;
verified = false; if (crc_pos < 0) {
} /* Single block */
} crc_pos = 0;
if (verified) { }
*nbytes = end_crc_pos - 2; memmove (res + crc_pos + 1, res + crc_pos, *nbytes - crc_pos);
((uint8_t *)data)[(*nbytes)++] = 0x00; ((uint8_t *)res)[crc_pos] = 0x00;
} else { crc_pos++;
end_crc_pos++; *nbytes += 1;
} break;
} while (!verified && (end_crc_pos < *nbytes)); }
if (!verified) {
#if WITH_DEBUG
warnx ("(3)DES not verified");
#endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1;
res = NULL;
}
break;
case AS_NEW:
mifare_cypher_blocks_chained (tag, NULL, NULL, res, *nbytes, MCD_RECEIVE, MCO_DECYPHER);
/*
* ,----------------------------+-----------------------------------------+-------------+
* \ BLOCK n-1 | BLOCK n | STATUS|
* / DATA | CRC0 | CRC1 | CRC2 | CRC3 | 0x80? | 0x00 | 0x00 | ... | 0x00 | 0x91 | 0x00 |
* `----------------------------+-----------------------------------------+-------------+
* <------------------------------ DATA --------------------------------->|
*
* <----------------- DATA ---------------->
* FRAME = PAYLOAD + CRC(PAYLOAD + STATUS) + PADDING + STATUS
* ^ |
* | |
* `------------------'
*/
/* Move status between payload and CRC */
res = assert_crypto_buffer_size (tag, (*nbytes) + 1);
memcpy (res, data, *nbytes);
int crc_pos = (*nbytes) - 16 - 3;
if (crc_pos < 0) {
/* Single block */
crc_pos = 0;
}
memmove (res + crc_pos + 1, res + crc_pos, *nbytes - crc_pos);
((uint8_t *)res)[crc_pos] = 0x00;
crc_pos++;
*nbytes += 1;
do { do {
uint16_t crc16;
uint32_t crc; uint32_t crc;
end_crc_pos = crc_pos + 4; switch (MIFARE_DESFIRE (tag)->authentication_scheme) {
desfire_crc32 (res, end_crc_pos, (uint8_t *)&crc); case AS_LEGACY:
end_crc_pos = crc_pos + 2;
iso14443a_crc (res, end_crc_pos, (uint8_t *)&crc16);
crc = crc16;
break;
case AS_NEW:
end_crc_pos = crc_pos + 4;
desfire_crc32 (res, end_crc_pos, (uint8_t *)&crc);
break;
}
if (!crc) { if (!crc) {
verified = true; verified = true;
for (int n = end_crc_pos; n < *nbytes - 1; n++) { for (int n = end_crc_pos; n < *nbytes - 1; n++) {
@ -609,26 +601,39 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
} }
} }
if (verified) { if (verified) {
*nbytes = crc_pos - 1; *nbytes = crc_pos;
switch (MIFARE_DESFIRE (tag)->authentication_scheme) {
case AS_LEGACY:
((uint8_t *)data)[(*nbytes)++] = 0x00; ((uint8_t *)data)[(*nbytes)++] = 0x00;
break;
case AS_NEW:
/* The status byte was already before the CRC */
break;
}
} else { } else {
uint8_t x = ((uint8_t *)res)[crc_pos - 1]; switch (MIFARE_DESFIRE (tag)->authentication_scheme) {
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos]; case AS_LEGACY:
((uint8_t *)res)[crc_pos] = x; break;
case AS_NEW:
x = ((uint8_t *)res)[crc_pos - 1];
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
((uint8_t *)res)[crc_pos] = x;
break;
}
crc_pos++; crc_pos++;
} }
} while (!verified && (end_crc_pos < *nbytes)); } while (!verified && (end_crc_pos < *nbytes));
if (!verified) { if (!verified) {
#if WITH_DEBUG #if WITH_DEBUG
hexdump (res, *nbytes, "KO ", 0); /* FIXME In some configurations, the file is transmitted PLAIN */
warnx ("AES not verified"); warnx ("CRC not verified in decyphered stream");
#endif #endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1; *nbytes = -1;
res = NULL; res = NULL;
} }
}
break; break;
default: default:
warnx ("Unknown communication settings"); warnx ("Unknown communication settings");