+ PrintAndLogEx(NORMAL, " BCC1 : %02X, crc should be %02X", data[8], crc1 );
+
+ PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " );
+
+ PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)",
+ sprint_hex(data+10, 2),
+ printBits(1, data+10),
+ printBits(1, data+11)
+ );
+
+ PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n",
+ sprint_hex(data+12, 4),
+ printBits(1, data+12),
+ printBits(1, data+13),
+ printBits(1, data+14),
+ printBits(1, data+15)
+ );
+
+ return 0;
+}
+
+
+static int ndef_print_CC(uint8_t *data) {
+ // no NDEF message
+ if(data[0] != 0xe1)
+ return -1;
+
+ PrintAndLogEx(NORMAL, "--- NDEF Message");
+ PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data,4) );
+ PrintAndLogEx(NORMAL, " %02X : NDEF Magic Number", data[0]);
+ PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
+ PrintAndLogEx(NORMAL, " %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8);
+ if ( data[2] == 0x12 )
+ PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 144);
+ else if ( data[2] == 0x3e )
+ PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 496);
+ else if ( data[2] == 0x6d )
+ PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 872);
+
+ PrintAndLogEx(NORMAL, " %02X : %s / %s", data[3],
+ (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security",
+ (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)");
+ return 0;
+}
+
+
+int ul_print_type(uint32_t tagtype, uint8_t spaces){
+ char spc[11] = " ";
+ spc[10]=0x00;
+ char *spacer = spc + (10-spaces);
+
+ if (tagtype & UL )
+ PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+ else if (tagtype & UL_C)
+ PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+ else if (tagtype & UL_EV1_48)
+ PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer);
+ else if (tagtype & UL_EV1_128)
+ PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer);
+ else if (tagtype & NTAG)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer);
+ else if (tagtype & NTAG_203)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer);
+ else if (tagtype & NTAG_210)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer);
+ else if (tagtype & NTAG_212)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer);
+ else if (tagtype & NTAG_213)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer);
+ else if (tagtype & NTAG_215)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer);
+ else if (tagtype & NTAG_216)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer);
+ else if (tagtype & NTAG_I2C_1K)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD");
+ else if (tagtype & NTAG_I2C_2K)
+ PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD");
+ else if (tagtype & MY_D)
+ PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer);
+ else if (tagtype & MY_D_NFC)
+ PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer);
+ else if (tagtype & MY_D_MOVE)
+ PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move | my-d\x99move NFC (SLE 66R01P)", spacer);
+ else if (tagtype & MY_D_MOVE_LEAN)
+ PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer);
+ else if (tagtype & FUDAN_UL)
+ PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "<magic>" : "" );
+ else
+ PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype);
+ return 0;
+}
+
+
+static int ulc_print_3deskey(uint8_t *data) {
+ PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data);
+ PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4);
+ PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8);
+ PrintAndLogEx(NORMAL, " deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12);
+ PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16));
+ return 0;
+}
+
+
+static int ulc_print_configuration(uint8_t *data) {
+
+ PrintAndLogEx(NORMAL, "--- UL-C Configuration");
+ PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)",
+ sprint_hex(data, 2),
+ printBits(1, data),
+ printBits(1, data+1)
+ );
+ PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s", sprint_hex(data+4, 2));
+
+ bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30);
+ if (validAuth)
+ PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] );
+ else{
+ if (data[8] == 0) {
+ PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) );
+ } else {
+ PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) );
+ }
+ }
+ PrintAndLogEx(NORMAL, " Auth1 [43/0x2B] : %s %s",
+ sprint_hex(data+12, 4),
+ (data[12] & 1) ? "write access restricted": "read and write access restricted"
+ );
+ return 0;
+}
+
+
+static int ulev1_print_configuration(uint8_t *data, uint8_t startPage) {
+
+ PrintAndLogEx(NORMAL, "\n--- Tag Configuration");
+
+ bool strg_mod_en = (data[0] & 2);
+ uint8_t authlim = (data[4] & 0x07);
+ bool cfglck = (data[4] & 0x40);
+ bool prot = (data[4] & 0x80);
+ uint8_t vctid = data[5];
+
+ PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4));
+ if (data[3] < 0xff)
+ PrintAndLogEx(NORMAL, " - page %d and above need authentication", data[3]);
+ else
+ PrintAndLogEx(NORMAL, " - pages don't need authentication");
+ PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled");
+ PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) );
+ if (authlim == 0)
+ PrintAndLogEx(NORMAL, " - Unlimited password attempts");
+ else
+ PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim);
+ PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable");
+ PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write");
+ PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not");
+ PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4));
+ PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2));
+ PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2));
+ return 0;
+}
+
+
+static int ulev1_print_counters(void) {
+ PrintAndLogEx(NORMAL, "--- Tag Counters");
+ uint8_t tear[1] = {0};
+ uint8_t counter[3] = {0,0,0};
+ uint16_t len = 0;
+ for ( uint8_t i = 0; i<3; ++i) {
+ ulev1_readTearing(i, tear, sizeof(tear));
+ len = ulev1_readCounter(i, counter, sizeof(counter) );
+ if (len == 3) {
+ PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3));
+ PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure");
+ }
+ }
+ return len;
+}
+
+
+static int ulev1_print_signature( uint8_t *data, uint8_t len){
+ PrintAndLogEx(NORMAL, "\n--- Tag Signature");
+ PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)");
+ PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN));
+ PrintAndLogEx(NORMAL, " Elliptic curve parameters : secp128r1");
+ PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(data, len));
+ //to do: verify if signature is valid
+ //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not");
+ return 0;
+}
+
+
+static int ulev1_print_version(uint8_t *data){
+ PrintAndLogEx(NORMAL, "\n--- Tag Version");
+ PrintAndLogEx(NORMAL, " Raw bytes : %s", sprint_hex(data, 8) );
+ PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1]));
+ PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2]));
+ PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF");
+ PrintAndLogEx(NORMAL, " Major version : %02X", data[4]);
+ PrintAndLogEx(NORMAL, " Minor version : %02X", data[5]);
+ PrintAndLogEx(NORMAL, " Size : %s", getUlev1CardSizeStr(data[6]));
+ PrintAndLogEx(NORMAL, " Protocol type : %02X", data[7]);
+ return 0;
+}
+
+
+static int ul_magic_test(void) {
+ // try a compatibility write to page0, and see if tag answers with ACK/NACK to the first part of the command
+ iso14a_card_select_t card;
+ if (!ul_select(&card, false))
+ return UL_ERROR;
+ int status = ul_comp_write_ex(0, NULL, 0, true);
+ if (status == 0) {
+ return MAGIC;
+ }
+ return 0;
+}
+
+
+uint32_t GetHF14AMfU_Type(void){
+
+ TagTypeUL_t tagtype = UNKNOWN;
+ iso14a_card_select_t card;
+ uint8_t version[10] = {0x00};
+ int len;
+
+ if (!ul_select(&card, true)) {
+ DropField();
+ msleep(200);
+ return UL_ERROR;
+ }
+
+ // Check for Ultralight Family
+ if (card.uidlen != 7 || (card.sak & 0x38) != 0x00) {
+ DropField();
+ PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak);
+ return UL_ERROR;
+ }
+
+ if (card.uid[0] != 0x05) {
+ len = ulev1_getVersion(version, sizeof(version));
+ if (len == 10) {
+ if (version[2] == 0x03 && version[6] == 0x0B)
+ tagtype = UL_EV1_48;
+ else if (version[2] == 0x03 && version[6] != 0x0B)
+ tagtype = UL_EV1_128;
+ else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B)
+ tagtype = NTAG_210;
+ else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E)
+ tagtype = NTAG_212;
+ else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F)
+ tagtype = NTAG_213;
+ else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11)
+ tagtype = NTAG_215;
+ else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13)
+ tagtype = NTAG_216;
+ else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13)
+ tagtype = NTAG_I2C_1K;
+ else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15)
+ tagtype = NTAG_I2C_2K;
+ else if (version[2] == 0x04)
+ tagtype = NTAG;
+ }
+
+ // UL vs UL-C vs ntag203 test
+ if (tagtype == UNKNOWN) {
+ ul_halt();
+ if (!ul_select(&card, false)) {
+ DropField();
+ msleep(200);
+ return UL_ERROR;
+ }
+
+ // do UL_C check first...
+ uint8_t nonce[11] = {0x00};
+ len = ulc_requestAuthentication(nonce, sizeof(nonce));
+ ul_halt();
+ if (len == 11) {
+ tagtype = UL_C;
+ } else {
+ // need to re-select after authentication error
+ if (!ul_select(&card, false)) {
+ DropField();
+ msleep(200);
+ return UL_ERROR;
+ }
+
+ uint8_t data[16] = {0x00};
+ // read page 0x29 (last valid ntag203 page)
+ len = ul_read(0x29, data, sizeof(data));
+ if (len <= 1) {
+ tagtype = UL;
+ } else {
+ // read page 0x30 (should error if it is a ntag203)
+ len = ul_read(0x30, data, sizeof(data));
+ if (len <= 1) {
+ ul_halt();
+ tagtype = NTAG_203;
+ }
+ }
+ }
+ }
+ if (tagtype & UL) {
+ tagtype = ul_fudan_check();
+ ul_halt();
+ }
+
+ } else { // manufacturer Infineon. Check for my-d variants
+
+ uint8_t nib = (card.uid[1] & 0xf0) >> 4;
+ switch (nib) {
+ case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes...
+ case 2: tagtype = MY_D_NFC; break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes)
+ case 3: tagtype = MY_D_MOVE; break; //or SLE 66R01P // 38 pages of 4 bytes
+ case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes
+ }
+ }
+
+ tagtype |= ul_magic_test();