0

I'm new to NFC Android and I was stuck for days trying to set a password for the NTAG216 Mifare Ultralight tag, I have a blank card and I'm trying to set it up and I assure you that there is no protection on the label but the command failed, I even did a search and found this link with examples but nothing worked for me, I still got the same error, I tried the tag on different devices but nothing, I really need help, if someone could help me please.

I specify that the writePage and readPages methods work correctly but it is with the transceive method works with the commands get_version and fast_read except when I try to define the password and the pack

package com.lancine.nfcapp;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.NfcA;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.ui.AppBarConfiguration;
import com.lancine.nfcapp.databinding.ActivityMainBinding;
import java.io.IOException;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback {

    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;
    NfcAdapter mAdapter;
    PendingIntent pendingIntent;
    Tag tag;

    @SuppressLint("UnspecifiedImmutableFlag")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE);
        } else {
            pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_ONE_SHOT);
        }

        mAdapter = NfcAdapter.getDefaultAdapter(this);
    }




    @Override
    protected void onResume() {
        super.onResume();
        //mAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
        if (mAdapter != null) {
            Bundle options = new Bundle();
            options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250);
            mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_NFC_B | NfcAdapter.FLAG_READER_NFC_F | NfcAdapter.FLAG_READER_NFC_V | NfcAdapter.FLAG_READER_NFC_BARCODE | NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS, options);
        }
    }

    @Override
    public void onTagDiscovered(Tag tag) {
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(VibrationEffect.createOneShot(150, 10));
        } else {
            Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
            v.vibrate(200);
        }

        this.setPassword(tag);
    }


    @Override
    protected void onPause() {
        super.onPause();
        if (mAdapter != null) {
            mAdapter.disableReaderMode(this);
        }
    }



    public void setPassword(Tag tag) {
        (new Thread(() -> {
            NfcA nfcA = null;
            try {
                nfcA = NfcA.get(tag);
                if(nfcA != null) {
                    nfcA.connect();
                    byte[] data = nfcA.transceive(new byte[] {
                            (byte)0xA2, // WRITE
                            (byte)(229 & 0x0ff), // block address
                            (byte)0x34, (byte)0x36, (byte)0x37, (byte)0x32
                    });
                    System.out.println("Comment" + Arrays.toString(data));
                    nfcA.close();
                }
            } catch (IOException e) {
                Log.e("TAG", "IOException", e);
                e.printStackTrace();
            }
        })).start();
    }
}

W/System.err: java.io.IOException: Transceive failed W/System.err: at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52) W/System.err: at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151) W/System.err: at android.nfc.tech.MifareUltralight.transceive(MifareUltralight.java:215) W/System.err: at com.lancine.nfcapp.MainActivity.lambda$nfcCommand$0$com-lancine-nfcapp-MainActivity(MainActivity.java:153) W/System.err: at com.lancine.nfcapp.MainActivity$$ExternalSyntheticLambda0.run(D8$$SyntheticClass) W/System.err: at java.lang.Thread.run(Thread.java:761)

The information I get when I read the card with nxp's TagInfo app

Detailed protocol information:

ID: 04:DE:58:42:EC:64:80 ATQA: 0x4400 SAK: 0x00

# Memory content:
[00] *  04:DE:58 0A (UID0-UID2, BCC0)
[01] *  42:EC:64:80 (UID3-UID6)
[02] .  4A 48 00 00 (BCC1, INT, LOCK0-LOCK1)
[03] .  E1:11:6D:00 (OTP0-OTP3)
[04] .  03 0B D1 01 |....|
[05] .  07 54 02 66 |.T.f|
[06] .  72 59 65 6F |rYeo|
[07] .  79 FE 00 00 |y...|
[08] .  32 22 2C 22 |2","|
[09] .  63 61 72 74 |cart|
[0A] .  5F 69 64 22 |_id"|
[0B] .  3A 22 31 30 |:"10|
[0C] .  30 30 30 30 |0000|
[0D] .  30 30 22 2C |00",|
[0E] .  22 65 74 61 |"eta|
[0F] .  62 5F 69 64 |b_id|
[10] .  22 3A 22 31 |":"1|
[11] .  30 30 30 30 |0000|
[12] .  30 30 22 2C |00",|
[13] .  22 65 74 61 |"eta|
[14] .  62 5F 6E 6F |b_no|
[15] .  6D 22 3A 22 |m":"|
[16] .  4C 59 43 45 |LYCE|

[E1] .r 00 00 00 00 |....|
[E2] .r 00 00 00 BD (LOCK2-LOCK4, CHK)
[E3] .r 04 00 00 E1 (CFG, MIRROR, AUTH0)
[E4] .r 00 05 -- -- (ACCESS)
[E5] +P XX XX XX XX (PWD0-PWD3)
[E6] +P XX XX -- -- (PACK0-PACK1)

  *:locked & blocked, x:locked,
  +:blocked, .:un(b)locked, ?:unknown
  r:readable (write-protected),
  p:password protected, -:write-only
  P:password protected write-only
  • And did you look at [this](https://stackoverflow.com/questions/17401154/android-nfc-java-io-ioexception-transceive-failed?rq=1) question? – Adam Nov 08 '22 at 16:00
  • @Adam Yes I looked at this question but it didn't help me, apparently that person would need to authenticate first, In my case there is no protection on the label and I just want to set the password goes and configures the card but I still can't do it – Lancine Yeo Nov 08 '22 at 17:20
  • I setup a complete example on how to set a password protection here: https://github.com/MichaelsPlayground/NfcNfcaAuthProtection/blob/master/app/src/main/java/de/androidcrypto/nfcnfcaauthprotection/SetWriteProtectionActivity.java (it is part of a complete app, disclaimer: I'm the author) – Michael Fehr Nov 08 '22 at 19:02
  • It might help if you show more of your code of how your get the `tag` object. – Andrew Nov 08 '22 at 20:07
  • @MichaelFehr, Thank you for your answer, I will look at your way of proceeding and get back to you, once again thank you – Lancine Yeo Nov 08 '22 at 20:20
  • @Andrew, Thank you for your answer, For the moment I am not in front of the computer, when I will be there, I will give this detail. thank you – Lancine Yeo Nov 08 '22 at 20:30
  • @MichaelFehr Hi, I followed your way but still got the same error, I even ran your source code to see I could configure the board with it but still got the same error with your code "java.io.IOException: Transceive failed". Thank you for your reply. – Lancine Yeo Nov 09 '22 at 11:37

1 Answers1

0

Update 2

Based on the updated details about the current state of the Ntag216 Tag, is this Tag is already write protected with a password, you cannot write a new password without authenticating with the old password by send the "auth" command 1Bh (see the datasheet for how to send the PWD_AUTH command)

You can see that byte 4 of block 0xE3h is set to start password protection at block 0xE1h instead of the default value of 0xFFh

This means the password config block (0xE3, 0xE5, 0xE6) is still write protected because they have a block address that is greater then the start block for password protection BUT most of the normal data area is read/write so you will still need the old password to write a new one.

Trying to write to a write password protected Tag will generate your IOException's

Original and still valid

So Technically an NTag216 is not a MifareUltralight, but it is compatible enough to one of the types of MifareUltralight to enumerate as that for more standard commands.

I personally don't bother using the MifareUltralight class for NTag216 Tags because as the documentation says:-

Implementation of this class on a Android NFC device is optional

Much better to use the lower level NfcA class for this type of Tag especially as you are just doing transceive as MifareUltralight class offers very little benefit and might not be implemented on all phones.

So may be try using the NfcA class instead?

Other points you should really check the return of the MifareUltralight mifare = MifareUltralight.get(this.tag); line (same goes for NfcA.get method) as it might actually return null as trying to call connect() on a null does not raise the only exception (IOException) you have caught.

If you don't do a null check a user presenting the wrong Tag type could crash you code.

e.g.

NfcA nfca = NfcA.get(this.tag);
if (ncfa != null) {
    try {
        nfca.connect();
    ......

Also using enableForegroundDispatch is not the best to use in real life as it leads to lots of failed writes with real users because they hear the notification sound the system makes when a Tag comes in to range and thinks the operations has been successful and removes the Tag from range before the write has a chance to write, this leads to lots of errors including lots of IOExceptions

So using enableReaderMode fixes all these problems because you can turn the sound off and then make your own notification when the write is successful.

But @Michael Fehr code looks good and implement all the best methods and correct error checking, etc, so if that does not work then that really only leaves a problem with physical positioning of the Tag.

If the Tag is no correctly positioned on the device then poor reception/power can cause IOException's

You don't specify the format of the NTag216, is it a small disk or puck or a large credit card format? I have some Ntag21x Tags that are a 10mm puck and they are way more picky about being centre of the NFC field than the credit card sized Ntag's I have (because the antenna they have is much smaller)

Find a dismantling video of your phone on YouTube to find out exactly where the NFC antenna is.

Or build a simple field detector to try and work out the centre of the antenna. e.g. https://www.youtube.com/watch?v=dTv4U5fotM0

Andrew
  • 8,198
  • 2
  • 15
  • 35
  • Thank you for your answer, I took your remarks into account but I still have the same error. I use PVC NFC Cards – Lancine Yeo Nov 10 '22 at 09:03
  • Hmm, have you used the nxp TagInfo to do a full read to check the Tag that it is not a clone by looking at the Originality Check and the pages you are trying to write are present and then used nxp TagWriter to protect a Tag with password? – Andrew Nov 10 '22 at 09:12
  • @Andew I added some captures to the question for you to watch, this is the card info pulled with nxp's TagInfo app, I tried setting a password on the tag with the TagWritter app , here is the error I get "This tag cannot be protected, (parts of) protected tag" Thanks for your effort – Lancine Yeo Nov 10 '22 at 11:06
  • Updated the answer based on the new info, the Tag is already write password protected, you cannot write without authenticating with the old password. Also NXP Taginfo App can save the scan as an XML file so you can include the Tag details as Text in your question as posting of pictures should be avoided. – Andrew Nov 10 '22 at 12:04
  • Thank you for your help, but sorry I realize that I got the wrong card, I made an update, on this one I can write without authenticating myself, except that the definition of the word pass is all a problem – Lancine Yeo Nov 10 '22 at 13:57
  • The new Tag data does not really change anything the password area is still write protected, I've updated the answer again. – Andrew Nov 10 '22 at 14:10
  • Really thank you very much for your help, I would like to know one thing, when we want to authenticate to a tag, we have the command and the password in bytes, the default tag password is FFFFFFFFh, what would be its value in byte or at least how I convert this value to byte. thank you. – Lancine Yeo Nov 10 '22 at 19:06
  • FFFFFFFFh is (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF – Andrew Nov 10 '22 at 20:10
  • Thank you again for your efforts but I cannot authenticate with the default password, `byte[] data = nfcA.transceive(new byte[] { (byte)0x1B, (byte)0xFF, (byte)0xFF (byte)0xFF, (byte)0xFF });` java.io.IOException: Transceive failed – Lancine Yeo Nov 10 '22 at 21:45
  • May be the password is not the default?, I don't know the history of this Tag. But a hint, if your programming is not working, try the action you are trying to perform on a Tag using one of the Apps from manufacturer or other good developer e.g. NXP's Taginfo and TagWriter or NFC Tools Apps. NFC tools even offers the ability to transceive custom commands as byte arrays. – Andrew Nov 11 '22 at 11:58
  • ok thank you i will do that and get back to you – Lancine Yeo Nov 11 '22 at 20:49
  • Hello, I used the NFC tools app and I was able to set a password, I really don't know why I can't do it with the code I wrote, so far I don't know what I'm doing wrong. – Lancine Yeo Nov 14 '22 at 07:04