Add support for authentication using 3K3DES.

Please note that according to the NXP documentation of the Mifare DESFire EV1,
the mifare_desfire_authenticate_iso() function can be used using either 3DES or
3K3DES keys.  The former has not been tested yet and is likely not to work. To
word it differently, this is a 3K3DES crypto support, not a ISO authentication
support...
This commit is contained in:
Romain Tartiere 2010-12-18 02:28:27 +00:00
parent f06b0ac5d3
commit d098bf623f
9 changed files with 939 additions and 13 deletions

View file

@ -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);

View file

@ -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;
};

View file

@ -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;

View file

@ -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:

View file

@ -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);