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:
parent
f06b0ac5d3
commit
d098bf623f
9 changed files with 939 additions and 13 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue