+ if (errors)
+ return usage_hf_mfu_info();
+
+ TagTypeUL_t tagtype = GetHF14AMfU_Type();
+ if (tagtype == UL_ERROR) {
+ return -1;
+ }
+
+ PrintAndLogEx(NORMAL, "\n--- Tag Information ---------");
+ PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
+ ul_print_type(tagtype, 6);
+
+ // Swap endianness
+ if (swapEndian && hasAuthKey)
+ authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4 );
+
+ if (!ul_auth_select(&card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) {
+ DropField();
+ return -1;
+ }
+
+ // read pages 0,1,2,3 (should read 4pages)
+ uint8_t data[16];
+ len = ul_read(0, data, sizeof(data));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to READ");
+ return -1;
+ } else if (len == 16) {
+ ul_print_default(data);
+ ndef_print_CC(data+12);
+ } else {
+ locked = true;
+ }
+
+ // UL_C Specific
+ if ((tagtype & UL_C)) {
+
+ // read pages 0x28, 0x29, 0x2A, 0x2B
+ uint8_t ulc_conf[16] = {0x00};
+ len = ul_read(0x28, ulc_conf, sizeof(ulc_conf));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C");
+ return -1;
+ }
+ if (len == 16) {
+ ulc_print_configuration(ulc_conf);
+ } else {
+ locked = true;
+ }
+
+ if ((tagtype & MAGIC)) {
+ //just read key
+ uint8_t ulc_deskey[16] = {0x00};
+ len = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic");
+ return -1;
+ }
+ if (len == 16) ulc_print_3deskey(ulc_deskey);
+ } else {
+ // if we called info with key, just return
+ if (hasAuthKey) {
+ DropField();
+ return 1;
+ }
+
+ // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys
+ PrintAndLogEx(INFO, "Trying some default 3des keys");
+ for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) {
+ uint8_t *key = default_3des_keys[i];
+ if (ulc_authentication(key, true)) {
+ DropField();
+ PrintAndLogEx(SUCCESS, "Found default 3des key: ");
+ uint8_t keySwap[16];
+ memcpy(keySwap, SwapEndian64(key,16,8), 16);
+ ulc_print_3deskey(keySwap);
+ return 1;
+ }
+ }
+ DropField();
+ return 1;
+ }
+ }
+
+ // do counters and signature first (don't neet auth)
+
+ // ul counters are different than ntag counters
+ if ((tagtype & (UL_EV1_48 | UL_EV1_128))) {
+ if (ulev1_print_counters() != 3) {
+ // failed - re-select
+ if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) {
+ DropField();
+ return -1;
+ }
+ }
+ }
+
+ if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) {
+ uint8_t ulev1_signature[32] = {0x00};
+ len = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE");
+ return -1;
+ }
+ if (len == 32) {
+ ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature));
+ } else {
+ // re-select
+ if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) {
+ DropField();
+ return -1;
+ }
+ }
+ }
+
+ if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_210 | NTAG_212 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K))) {
+ uint8_t version[10] = {0x00};
+ len = ulev1_getVersion(version, sizeof(version));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION");
+ return -1;
+ } else if (len == 10) {
+ ulev1_print_version(version);
+ } else {
+ locked = true;
+ if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) {
+ DropField();
+ return -1;
+ }
+ }
+
+ uint8_t startconfigblock = 0;
+ uint8_t ulev1_conf[16] = {0x00};
+ // config blocks always are last 4 pages
+ for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) {
+ if (tagtype & UL_TYPES_ARRAY[idx]) {
+ startconfigblock = UL_MEMORY_ARRAY[idx]-3;
+ break;
+ }
+ }
+
+ if (startconfigblock) { // if we know where the config block is...
+ len = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf));
+ if (len == -1) {
+ DropField();
+ PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1");
+ return -1;
+ } else if (len == 16) {
+ // save AUTHENTICATION LIMITS for later:
+ authlim = (ulev1_conf[4] & 0x07);
+ ulev1_print_configuration(ulev1_conf, startconfigblock);
+ }
+ }
+
+ // AUTHLIMIT, (number of failed authentications)
+ // 0 = limitless.
+ // 1-7 = limit. No automatic tries then.
+ // hasAuthKey, if we was called with key, skip test.
+ if (!authlim && !hasAuthKey) {
+ PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords.");
+ len = 0;
+ for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) {
+ uint8_t *key = default_pwd_pack[i];
+ len = ulev1_requestAuthentication(key, pack, sizeof(pack));
+ if (len >= 1) {
+ PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
+ break;
+ } else {
+ if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) {
+ DropField();
+ return -1;
+ }
+ }
+ }
+ if (len < 1) PrintAndLogEx(WARNING, "password not known");
+ }
+ }
+
+ DropField();
+
+ if (locked)
+ PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info");
+ PrintAndLogEx(NORMAL, "");
+
+ return 1;
+}
+
+//
+// Write Single Block
+//
+static int usage_hf_mfu_wrbl(void) {
+ PrintAndLogEx(NORMAL, "Write a block. It autodetects card type.\n");
+ PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b <block number> d <data> k <key> l\n");
+ PrintAndLogEx(NORMAL, " Options:");
+ PrintAndLogEx(NORMAL, " b <no> : block to write");
+ PrintAndLogEx(NORMAL, " d <data> : block data - (8 hex symbols)");
+ PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
+ PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(NORMAL, " sample : hf mfu wrbl b 0 d 01234567");
+ PrintAndLogEx(NORMAL, " : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n");
+ return 0;
+}
+
+
+static int CmdHF14AMfUWrBl(const char *Cmd){
+
+ int blockNo = -1;
+ bool errors = false;
+ uint8_t keybytes[16] = {0x00};
+ uint8_t *authenticationkey = keybytes;
+ int keyLen = 0;
+ bool hasAuthKey = false;
+ bool swapEndian = false;
+ uint8_t cmdp = 0;
+ uint8_t blockdata[20] = {0x00};
+
+ while(param_getchar(Cmd, cmdp) != 0x00) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'h':
+ case 'H':
+ return usage_hf_mfu_wrbl();
+ case 'k':
+ case 'K':
+ keyLen = 32;
+ errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen);
+ if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length
+ PrintAndLogEx(ERR, "Key has incorrect length.\n");
+ errors = true;
+ }
+ cmdp += 2;
+ keyLen /= 2;
+ hasAuthKey = true;
+ break;
+ case 'b':
+ case 'B':
+ blockNo = param_get8(Cmd, cmdp+1);
+ if (blockNo < 0) {
+ PrintAndLogEx(ERR, "Wrong block number");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'l':
+ case 'L':
+ swapEndian = true;
+ cmdp++;
+ break;
+ case 'd':
+ case 'D':
+ if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) {
+ PrintAndLogEx(ERR, "Block data must include 8 HEX symbols");
+ errors = true;
+ break;
+ }
+ cmdp += 2;
+ break;
+ default:
+ PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ //Validations
+ if(errors) return usage_hf_mfu_wrbl();
+ }
+
+ if (blockNo == -1) return usage_hf_mfu_wrbl();
+ // starting with getting tagtype
+ TagTypeUL_t tagtype = GetHF14AMfU_Type();
+ if (tagtype == UL_ERROR) {
+ return -1;
+ }
+
+ uint8_t maxblockno = 0;
+ for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) {
+ if (tagtype & UL_TYPES_ARRAY[idx]) {
+ maxblockno = UL_MEMORY_ARRAY[idx];
+ break;
+ }
+ }
+ if (blockNo > maxblockno){
+ DropField();
+ PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno);
+ return usage_hf_mfu_wrbl();
+ }
+
+ // Swap endianness
+ if (swapEndian && hasAuthKey) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4);
+
+ if ( blockNo <= 3)
+ PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
+ else
+ PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4));
+
+ //Send write Block
+ UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
+ memcpy(c.d.asBytes, blockdata, 4);
+
+ if (hasAuthKey) {
+ c.arg[1] = (keyLen == 16) ? 1 : 2;
+ memcpy(c.d.asBytes+4, authenticationkey, keyLen);
+ }
+
+ clearCommandBuffer();
+ SendCommand(&c);
+ UsbCommand resp;
+ if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
+ uint8_t isOK = resp.arg[0] & 0xff;
+ PrintAndLogEx(SUCCESS, "isOk:%02x", isOK);
+ } else {
+ PrintAndLogEx(ERR, "Command execute timeout");
+ }
+
+ DropField();
+ return 0;
+}
+
+
+//
+// Read Single Block
+//
+static int usage_hf_mfu_rdbl(void) {
+ PrintAndLogEx(NORMAL, "Read a block and print. It autodetects card type.\n");
+ PrintAndLogEx(NORMAL, "Usage: hf mfu rdbl b <block number> k <key> l\n");
+ PrintAndLogEx(NORMAL, " Options:");
+ PrintAndLogEx(NORMAL, " b <no> : block to read");
+ PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
+ PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
+ PrintAndLogEx(NORMAL, "");
+ PrintAndLogEx(NORMAL, " sample : hf mfu rdbl b 0");
+ PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF");
+ PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k AABBCCDDD\n");
+ return 0;
+}
+
+
+static int CmdHF14AMfURdBl(const char *Cmd){
+
+ int blockNo = -1;
+ bool errors = false;
+ uint8_t keybytes[16] = {0x00};
+ uint8_t *authenticationkey = keybytes;
+ int keyLen = 0;
+ bool hasAuthKey = false;
+ bool swapEndian = false;
+ uint8_t cmdp = 0;
+
+ while(param_getchar(Cmd, cmdp) != 0x00)