Add support for Ultralight NTAG213/215/216
This commit is contained in:
parent
216145fba5
commit
62f27c1c58
2 changed files with 138 additions and 17 deletions
|
@ -9,7 +9,7 @@
|
|||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2017 Adam Laurie
|
||||
* Copyright (C) 2017-2018 Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -167,10 +167,62 @@ typedef struct {
|
|||
uint8_t dummy[12];
|
||||
} mifareul_block_config21B;
|
||||
|
||||
// MIFARE NTAG21[3/5/6] Manufacturer Pages
|
||||
typedef struct {
|
||||
uint8_t sn0[4];
|
||||
} mifarentag_block_manuf21356A;
|
||||
typedef struct {
|
||||
uint8_t sn1[4];
|
||||
} mifarentag_block_manuf21356B;
|
||||
typedef struct {
|
||||
uint8_t sn2;
|
||||
uint8_t internal;
|
||||
uint8_t lock[2];
|
||||
} mifarentag_block_manuf21356C;
|
||||
typedef struct {
|
||||
uint8_t cc[4];
|
||||
} mifarentag_block_manuf21356D;
|
||||
|
||||
// MIFARE NTAG21[3/5/6] Config Pages
|
||||
typedef struct {
|
||||
uint8_t dynlock[3];
|
||||
uint8_t rfui0;
|
||||
} mifarentag_block_config21356A;
|
||||
typedef struct {
|
||||
uint8_t cfg0[4];
|
||||
} mifarentag_block_config21356B;
|
||||
typedef struct {
|
||||
uint8_t cfg1[4];
|
||||
} mifarentag_block_config21356C;
|
||||
typedef struct {
|
||||
uint8_t pwd[4];
|
||||
} mifarentag_block_config21356D;
|
||||
typedef struct {
|
||||
uint8_t pack[2];
|
||||
uint8_t rfui1[2];
|
||||
} mifarentag_block_config21356E;
|
||||
|
||||
typedef struct {
|
||||
uint8_t abtData[16];
|
||||
} mifareul_block_data;
|
||||
|
||||
typedef struct {
|
||||
uint8_t abtData[4];
|
||||
} mifarentag_block_data;
|
||||
|
||||
typedef union {
|
||||
mifarentag_block_manuf21356A mbm21356a;
|
||||
mifarentag_block_manuf21356B mbm21356b;
|
||||
mifarentag_block_manuf21356C mbm21356c;
|
||||
mifarentag_block_manuf21356D mbm21356d;
|
||||
mifarentag_block_data mbd;
|
||||
mifarentag_block_config21356A mbc21356a;
|
||||
mifarentag_block_config21356B mbc21356b;
|
||||
mifarentag_block_config21356C mbc21356c;
|
||||
mifarentag_block_config21356D mbc21356d;
|
||||
mifarentag_block_config21356E mbc21356e;
|
||||
} mifarentag_block;
|
||||
|
||||
typedef union {
|
||||
mifareul_block_manufacturer mbm;
|
||||
mifareul_block_data mbd;
|
||||
|
@ -194,6 +246,43 @@ typedef struct {
|
|||
mifareul_block amb[11];
|
||||
} mifareul_ev1_mf0ul21_tag;
|
||||
|
||||
// NOT really UL but so similar we can re-use this code
|
||||
// if Edwin van Andel doesn't distract us...
|
||||
// https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf
|
||||
|
||||
// NTAG213 EEPROM: 180 bytes, organized in 45 pages of 4 byte per page.
|
||||
// 26 bytes reserved for manufacturer and configuration data
|
||||
// 34 bits used for the read-only locking mechanism
|
||||
// 4 bytes available as capability container
|
||||
// 144 bytes user programmable read/write memory
|
||||
typedef struct {
|
||||
mifarentag_block amb[45];
|
||||
} mifarentag_213_tag;
|
||||
|
||||
// NTAG215 EEPROM: 540 bytes, organized in 135 pages of 4 byte per page.
|
||||
// 26 bytes reserved for manufacturer and configuration data
|
||||
// 28 bits used for the read-only locking mechanism
|
||||
// 4 bytes available as capability container
|
||||
// 504 bytes user programmable read/write memory
|
||||
typedef struct {
|
||||
mifarentag_block amb[135];
|
||||
} mifarentag_215_tag;
|
||||
|
||||
// NTAG216 EEPROM: 924 bytes, organized in 231 pages of 4 byte per page.
|
||||
// 26 bytes reserved for manufacturer and configuration data
|
||||
// 37 bits used for the read-only locking mechanism
|
||||
// 4 bytes available as capability container
|
||||
// 888 bytes user programmable read/write memory
|
||||
typedef struct {
|
||||
mifarentag_block amb[231];
|
||||
} mifarentag_216_tag;
|
||||
|
||||
// dummy max size with all structures in it for reading, rounded up to a multiple of 16 bytes
|
||||
typedef union {
|
||||
mifareul_block ul[58];
|
||||
mifarentag_block nt[232];
|
||||
} maxtag;
|
||||
|
||||
// Reset struct alignment to default
|
||||
# pragma pack()
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||
* See AUTHORS file for a more comprehensive list of contributors.
|
||||
* Additional contributors of this file:
|
||||
* Copyright (C) 2013-2017 Adam Laurie
|
||||
* Copyright (C) 2013-2018 Adam Laurie
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
|
@ -64,11 +64,14 @@
|
|||
#define EV1_NONE 0
|
||||
#define EV1_UL11 1
|
||||
#define EV1_UL21 2
|
||||
#define EV1_NTAG213 3
|
||||
#define EV1_NTAG215 4
|
||||
#define EV1_NTAG216 5
|
||||
|
||||
static nfc_device *pnd;
|
||||
static nfc_target nt;
|
||||
static mifare_param mp;
|
||||
static mifareul_ev1_mf0ul21_tag mtDump; // use the largest tag type for internal storage
|
||||
static maxtag mtDump; // use the largest tag type for internal storage
|
||||
static uint32_t uiBlocks = 0x10;
|
||||
static uint32_t uiReadPages = 0;
|
||||
static uint8_t iPWD[4] = { 0x0 };
|
||||
|
@ -119,7 +122,7 @@ read_card(void)
|
|||
for (page = 0; page < uiBlocks; page += 4) {
|
||||
// Try to read out the data block
|
||||
if (nfc_initiator_mifare_cmd(pnd, MC_READ, page, &mp)) {
|
||||
memcpy(mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, uiBlocks - page < 4 ? (uiBlocks - page) * 4 : 16);
|
||||
memcpy(mtDump.ul[page / 4].mbd.abtData, mp.mpd.abtData, uiBlocks - page < 4 ? (uiBlocks - page) * 4 : 16);
|
||||
} else {
|
||||
bFailure = true;
|
||||
}
|
||||
|
@ -134,12 +137,24 @@ read_card(void)
|
|||
// copy EV1 secrets to dump data
|
||||
switch (iEV1Type) {
|
||||
case EV1_UL11:
|
||||
memcpy(mtDump.amb[4].mbc11.pwd, iPWD, 4);
|
||||
memcpy(mtDump.amb[4].mbc11.pack, iPACK, 2);
|
||||
memcpy(mtDump.ul[4].mbc11.pwd, iPWD, 4);
|
||||
memcpy(mtDump.ul[4].mbc11.pack, iPACK, 2);
|
||||
break;
|
||||
case EV1_UL21:
|
||||
memcpy(mtDump.amb[9].mbc21a.pwd, iPWD, 4);
|
||||
memcpy(mtDump.amb[9].mbc21b.pack, iPACK, 2);
|
||||
memcpy(mtDump.ul[9].mbc21a.pwd, iPWD, 4);
|
||||
memcpy(mtDump.ul[9].mbc21b.pack, iPACK, 2);
|
||||
break;
|
||||
case EV1_NTAG213:
|
||||
memcpy(mtDump.nt[43].mbc21356d.pwd, iPWD, 4);
|
||||
memcpy(mtDump.nt[44].mbc21356e.pack, iPACK, 2);
|
||||
break;
|
||||
case EV1_NTAG215:
|
||||
memcpy(mtDump.nt[133].mbc21356d.pwd, iPWD, 4);
|
||||
memcpy(mtDump.nt[134].mbc21356e.pack, iPACK, 2);
|
||||
break;
|
||||
case EV1_NTAG216:
|
||||
memcpy(mtDump.nt[229].mbc21356d.pwd, iPWD, 4);
|
||||
memcpy(mtDump.nt[230].mbc21356e.pack, iPACK, 2);
|
||||
break;
|
||||
case EV1_NONE:
|
||||
default:
|
||||
|
@ -386,7 +401,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid)
|
|||
// page (4 bytes). The Ultralight-specific Write command only
|
||||
// writes one page at a time.
|
||||
uiBlock = page / 4;
|
||||
memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 4);
|
||||
memcpy(mp.mpd.abtData, mtDump.ul[uiBlock].mbd.abtData + ((page % 4) * 4), 4);
|
||||
memset(mp.mpd.abtData + 4, 0, 12);
|
||||
if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp))
|
||||
bFailure = true;
|
||||
|
@ -470,7 +485,7 @@ int
|
|||
main(int argc, const char *argv[])
|
||||
{
|
||||
int iAction = 0;
|
||||
uint8_t iDumpSize = sizeof(mifareul_tag);
|
||||
size_t iDumpSize = sizeof(mifareul_tag);
|
||||
uint8_t iUID[MAX_UID_LEN] = { 0x0 };
|
||||
size_t szUID = 0;
|
||||
bool bOTP = false;
|
||||
|
@ -601,19 +616,36 @@ main(int argc, const char *argv[])
|
|||
if (get_ev1_version()) {
|
||||
if (!bPWD)
|
||||
printf("Tag is EV1 - PASSWORD may be required\n");
|
||||
printf("EV1 storage size: ");
|
||||
printf("EV1 type: ");
|
||||
if (abtRx[6] == 0x0b) {
|
||||
printf("48 bytes\n");
|
||||
uiBlocks = 0x14;
|
||||
printf("MF0UL11 (48 bytes)\n");
|
||||
uiBlocks = 20; // total number of 4 byte 'pages'
|
||||
iEV1Type = EV1_UL11;
|
||||
iDumpSize = sizeof(mifareul_ev1_mf0ul11_tag);
|
||||
} else if (abtRx[6] == 0x0e) {
|
||||
printf("128 bytes\n");
|
||||
uiBlocks = 0x29;
|
||||
printf("MF0UL21 (128 user bytes)\n");
|
||||
uiBlocks = 41;
|
||||
iEV1Type = EV1_UL21;
|
||||
iDumpSize = sizeof(mifareul_ev1_mf0ul21_tag);
|
||||
} else
|
||||
printf("unknown!\n");
|
||||
} else if (abtRx[6] == 0x0f) {
|
||||
printf("NTAG213 (144 user bytes)\n");
|
||||
uiBlocks = 45;
|
||||
iEV1Type = EV1_NTAG213;
|
||||
iDumpSize = sizeof(mifarentag_213_tag);
|
||||
} else if (abtRx[6] == 0x11) {
|
||||
printf("NTAG215 (504 user bytes)\n");
|
||||
uiBlocks = 135;
|
||||
iEV1Type = EV1_NTAG215;
|
||||
iDumpSize = sizeof(mifarentag_215_tag);
|
||||
} else if (abtRx[6] == 0x13) {
|
||||
printf("NTAG216 (888 user bytes)\n");
|
||||
uiBlocks = 231;
|
||||
iEV1Type = EV1_NTAG216;
|
||||
iDumpSize = sizeof(mifarentag_216_tag);
|
||||
} else {
|
||||
printf("unknown! (0x%02x)\n", abtRx[6]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
// re-init non EV1 tag
|
||||
if (nfc_initiator_select_passive_target(pnd, nmMifare, (szUID) ? iUID : NULL, szUID, &nt) <= 0) {
|
||||
|
|
Loading…
Reference in a new issue