/* * Free the provided tag. */ void mifare_desfire_tag_free (MifareTag tag) { free (MIFARE_DESFIRE (tag)->session_key); free (MIFARE_DESFIRE (tag)->last_pcd_error); free (MIFARE_DESFIRE (tag)->crypto_buffer); free (tag); }
int mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_key, MifareDESFireKey old_key) { ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); ASSERT_AUTHENTICATED (tag); BUFFER_INIT (cmd, 1+1+24); BUFFER_INIT (res, 1); BUFFER_APPEND (cmd, 0xC4); BUFFER_APPEND (cmd, key_no); uint8_t data[24]; if ((MIFARE_DESFIRE (tag)->authenticated_key_no != key_no) /* FIXME && (ChangeKey key != 0x0E)*/) { if (old_key) { memcpy (data, old_key->data, 16); } else { bzero (data, 16); } for (int n=0; n<16; n++) { data[n] ^= new_key->data[n]; } // Append XORed data CRC iso14443a_crc (data, 16, data+16); // Append new key CRC iso14443a_crc (new_key->data, 16, data+18); // Padding for (int n=20; n<24; n++) { data[n] = 0x00; } } else { memcpy (data, new_key->data, 16); // Append new key CRC iso14443a_crc (data, 16, data+16); // Padding for (int n=18; n<24; n++) { data[n] = 0x00; } } mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, data, 24, MD_SEND, 0); BUFFER_APPEND_BYTES (cmd, data, 24); DESFIRE_TRANSCEIVE (tag, cmd, res); return 0; }
/* * Terminate connection with the provided tag. */ int mifare_desfire_disconnect (MifareTag tag) { ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); free (MIFARE_DESFIRE (tag)->session_key); MIFARE_DESFIRE(tag)->session_key = NULL; if (nfc_initiator_deselect_target (tag->device)) { tag->active = 0; } return 0; }
int madame_soleil_get_write_communication_settings (MifareTag tag, uint8_t file_no) { // FIXME: It might be forbiden to get file settings. struct mifare_desfire_file_settings settings; if (mifare_desfire_get_file_settings (tag, file_no, &settings)) return -1; if ((MIFARE_DESFIRE (tag)->authenticated_key_no == MDAR_WRITE (settings.access_rights)) || (MIFARE_DESFIRE (tag)->authenticated_key_no == MDAR_READ_WRITE (settings.access_rights))) return settings.communication_settings; else return 0; }
int mifare_desfire_change_key_settings (MifareTag tag, uint8_t settings) { ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); ASSERT_AUTHENTICATED (tag); BUFFER_INIT (cmd, 9); BUFFER_INIT (res, 1); BUFFER_APPEND (cmd, 0x54); uint8_t data[8]; data[0] = settings; iso14443a_crc (data, 1, data + 1); bzero (data+3, 5); mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, data, 8, MD_SEND, 0); BUFFER_APPEND_BYTES (cmd, data, 8); DESFIRE_TRANSCEIVE (tag, cmd, res); return 0; }
uint8_t mifare_desfire_last_picc_error (MifareTag tag) { if (tag->tag_info->type != DESFIRE) return 0; return MIFARE_DESFIRE (tag)->last_picc_error; }
const char * freefare_strerror (FreefareTag tag) { const char *p = "Unknown error"; if (nfc_device_get_last_error (tag->device) < 0) { p = nfc_strerror (tag->device); } else { if (tag->tag_info->type == MIFARE_DESFIRE) { if (MIFARE_DESFIRE (tag)->last_pcd_error) { p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_pcd_error); } else if (MIFARE_DESFIRE (tag)->last_picc_error) { p = mifare_desfire_error_lookup (MIFARE_DESFIRE (tag)->last_picc_error); } } } return p; }
/* * Establish connection to the provided tag. */ int mifare_desfire_connect (MifareTag tag) { ASSERT_INACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); nfc_target_info_t pnti; if (nfc_initiator_select_passive_target (tag->device, NM_ISO14443A_106, tag->info.abtUid, 7, &pnti)) { tag->active = 1; free (MIFARE_DESFIRE (tag)->session_key); MIFARE_DESFIRE (tag)->session_key = NULL; MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; MIFARE_DESFIRE (tag)->last_pcd_error = NULL; MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED; } else { errno = EIO; return -1; } return 0; }
/* * Allocates and initialize a MIFARE DESFire tag. */ MifareTag mifare_desfire_tag_new (uint32_t aFd) { nfc_iso14443a_info_t dummy_info; MifareTag tag; if ((tag= malloc (sizeof (struct mifare_desfire_tag)))) { MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; MIFARE_DESFIRE (tag)->last_pcd_error = NULL; MIFARE_DESFIRE (tag)->session_key = NULL; MIFARE_DESFIRE (tag)->crypto_buffer = NULL; MIFARE_DESFIRE (tag)->crypto_buffer_size = 0; device.ui8TxBits = aFd; tag->device = &device; tag->info = dummy_info; tag->active = 0; tag->tag_info = supported_tags_jim + 3; } return tag; }
static ssize_t write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t length, void *data, int cs) { size_t bytes_left; size_t bytes_send = 0; void *p = data; ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); BUFFER_INIT (cmd, MAX_FRAME_SIZE); 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)); p = mifare_cryto_preprocess_data (tag, data, &length, cs); bytes_left = 52; while (bytes_send < length) { size_t frame_bytes = MIN(bytes_left, length - bytes_send); BUFFER_APPEND_BYTES (cmd, (uint8_t *)p + bytes_send, frame_bytes); DESFIRE_TRANSCEIVE (tag, cmd, res); bytes_send += frame_bytes; if (0x00 == res[0]) break; // PICC returned 0xAF and expects more data BUFFER_CLEAR (cmd); BUFFER_APPEND (cmd, 0xAF); bytes_left = 0x59; } if (0x00 != res[0]) { // 0xAF (additionnal Frame) failure can happen here (wrong crypto method). MIFARE_DESFIRE (tag)->last_picc_error = res[0]; bytes_send = -1; } return bytes_send; }
int mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t communication_settings, uint16_t access_rights) { ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); // TODO: Use a current application files settings cache. struct mifare_desfire_file_settings settings; int res = mifare_desfire_get_file_settings (tag, file_no, &settings); if (res < 0) return res; if (MDAR_CHANGE_AR(settings.access_rights) == MDAR_FREE) { BUFFER_INIT (cmd, 5); BUFFER_INIT (res, 1); BUFFER_APPEND (cmd, 0x5F); BUFFER_APPEND (cmd, file_no); BUFFER_APPEND (cmd, communication_settings); BUFFER_APPEND_LE (cmd, access_rights, 2, sizeof (uint16_t)); DESFIRE_TRANSCEIVE (tag, cmd, res); } else { BUFFER_INIT (cmd, 10); BUFFER_INIT (res, 1); uint8_t data[8]; BUFFER_APPEND (cmd, 0x5F); BUFFER_APPEND (cmd, file_no); data[0] = communication_settings; uint16_t le_ar = htole16 (access_rights); memcpy (data + 1, &le_ar, sizeof (le_ar)); iso14443a_crc (data, 3, data+3); bzero (data + 5, 3); mifare_cbc_des (MIFARE_DESFIRE (tag)->session_key, data, 8, MD_SEND, 0); BUFFER_APPEND_BYTES (cmd, data, 8); DESFIRE_TRANSCEIVE (tag, cmd, res); } return 0; }
int mifare_desfire_authenticate (MifareTag tag, uint8_t key_no, MifareDESFireKey key) { ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED; free (MIFARE_DESFIRE (tag)->session_key); MIFARE_DESFIRE (tag)->session_key = NULL; BUFFER_INIT (cmd1, 2); BUFFER_INIT (res, 9); BUFFER_APPEND (cmd1, 0x0A); BUFFER_APPEND (cmd1, key_no); DESFIRE_TRANSCEIVE (tag, cmd1, res); uint8_t PICC_E_RndB[8]; memcpy (PICC_E_RndB, res+1, 8); uint8_t PICC_RndB[8]; memcpy (PICC_RndB, PICC_E_RndB, 8); mifare_cbc_des (key, PICC_RndB, 8, MD_RECEIVE, 0); uint8_t PCD_RndA[8]; DES_random_key ((DES_cblock*)&PCD_RndA); uint8_t PCD_r_RndB[8]; memcpy (PCD_r_RndB, PICC_RndB, 8); rol8 (PCD_r_RndB); uint8_t token[16]; memcpy (token, PCD_RndA, 8); memcpy (token+8, PCD_r_RndB, 8); mifare_cbc_des (key, token, 16, MD_SEND, 0); BUFFER_INIT (cmd2, 17); BUFFER_APPEND (cmd2, 0xAF); BUFFER_APPEND_BYTES (cmd2, token, 16); DESFIRE_TRANSCEIVE (tag, cmd2, res); uint8_t PICC_E_RndA_s[8]; memcpy (PICC_E_RndA_s, res+1, 8); uint8_t PICC_RndA_s[8]; memcpy (PICC_RndA_s, PICC_E_RndA_s, 8); mifare_cbc_des (key, PICC_RndA_s, 8, MD_RECEIVE, 0); uint8_t PCD_RndA_s[8]; memcpy (PCD_RndA_s, PCD_RndA, 8); rol8 (PCD_RndA_s); if (0 != memcmp (PCD_RndA_s, PICC_RndA_s, 8)) { printf ("PCD_RndA_s != PICC_RndA_s"); return -1; } MIFARE_DESFIRE (tag)->authenticated_key_no = key_no; MIFARE_DESFIRE (tag)->session_key = mifare_desfire_session_key_new (PCD_RndA, PICC_RndB, key); return 0; }
uint8_t mifare_desfire_get_last_error (MifareTag tag) { return MIFARE_DESFIRE (tag)->last_picc_error; }