+ 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(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len){
+ uint8_t public_key = 0;
+ if (tagtype == UL_EV1_48 || tagtype == UL_EV1_128) {
+ public_key = 1;
+ }
+ int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, public_keys[public_key], uid, 7, signature, signature_len, false);
+ bool signature_valid = (res == 0);