Setting NTAG213 password in Android with MifareUltralight.transceive crashes, no exception thrown

自古美人都是妖i 提交于 2019-12-11 08:32:37

问题


I'm trying to set a password on my empty NTAG213 tags, but when I get to writing the PACK and PWD my app just crashes, with no exception thrown. I did get my app far enough to write valid NDEF messages and read those, it seems I can also write to other configuration pages(2Ah and 29h for configurating the password protection). When I get to writing PACK though, my app crashes but doesn't throw the IOException I would expect from MifareUltralight.transceive(byte[] data).

Here is the souce code for my writeAndProtect method:

private void writeAndProtectTag(final Intent intent, final String message) {
    // Run the entire process in its own thread as MifareUltralight.transceive(byte[] data);
    // Should not be run in main thread according to <https://developer.android.com/reference/android/nfc/tech/MifareUltralight.html#transceive(byte[])>
    (new Thread(new Runnable() {
        // Password has to be 4 characters
        // Password Acknowledge has to be 2 characters
        byte[] pwd      = "-_bA".getBytes();
        byte[] pack     = "cC".getBytes();

        @Override
        public void run() {
            // Store tag object for use in MifareUltralight and Ndef
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            MifareUltralight mifare = null;
            int debugCounter = 0;

            // Whole process is put into a big try-catch trying to catch the transceive's IOException
            try {
                mifare = MifareUltralight.get(tag);

                mifare.connect();
                while(!mifare.isConnected());
                byte[] response;

                // Authenticate with the tag first
                // In case it's already been locked
                try {
                    response = mifare.transceive(new byte[]{
                            (byte) 0x1B, // PWD_AUTH
                            pwd[0], pwd[1], pwd[2], pwd[3]
                    });
                    // Check if PACK is matching expected PACK
                    // This is a (not that) secure method to check if tag is genuine
                    if ((response != null) && (response.length >= 2)) {
                        byte[] packResponse = Arrays.copyOf(response, 2);
                        if (!(pack[0] == packResponse[0] && pack[1] == packResponse[1])) {
                            Toast.makeText(ctx, "Tag could not be authenticated:\n" + packResponse.toString() + "≠" + pack.toString(), Toast.LENGTH_LONG).show();
                        }
                    }
                }catch(IOException e){
                    e.printStackTrace();
                }

                // Get Page 2Ah
                response = mifare.transceive(new byte[] {
                        (byte) 0x30, // READ
                        (byte) 0x2A  // page address
                });
                // configure tag as write-protected with unlimited authentication tries
                if ((response != null) && (response.length >= 16)) {    // read always returns 4 pages
                    boolean prot = false;                               // false = PWD_AUTH for write only, true = PWD_AUTH for read and write
                    int authlim = 0;                                    // 0 = unlimited tries
                    mifare.transceive(new byte[] {
                            (byte) 0xA2, // WRITE
                            (byte) 0x2A, // page address
                            (byte) ((response[0] & 0x078) | (prot ? 0x080 : 0x000) | (authlim & 0x007)),    // set ACCESS byte according to our settings
                            0, 0, 0                                                                         // fill rest as zeros as stated in datasheet (RFUI must be set as 0b)
                    });
                }
                // Get page 29h
                response = mifare.transceive(new byte[] {
                        (byte) 0x30, // READ
                        (byte) 0x29  // page address
                });
                // Configure tag to protect entire storage (page 0 and above)
                if ((response != null) && (response.length >= 16)) {  // read always returns 4 pages
                    int auth0 = 0;                                    // first page to be protected
                    mifare.transceive(new byte[] {
                            (byte) 0xA2, // WRITE
                            (byte) 0x29, // page address
                            response[0], 0, response[2],              // Keep old mirror values and write 0 in RFUI byte as stated in datasheet
                            (byte) (auth0 & 0x0ff)
                    });
                }

                // Send PACK and PWD
                // set PACK:
                mifare.transceive(new byte[] {
                        (byte)0xA2,
                        (byte)0x2C,
                        pack[0], pack[1], 0, 0  // Write PACK into first 2 Bytes and 0 in RFUI bytes
                });
                // set PWD:
                mifare.transceive(new byte[] {
                        (byte)0xA2,
                        (byte)0x2B,
                        pwd[0], pwd[1], pwd[2], pwd[3] // Write all 4 PWD bytes into Page 43
                });

            } catch (IOException e) {
                //Trying to catch any exception that may be thrown
                e.printStackTrace();
            } catch (Exception e) {
                //Trying to catch any exception that may be thrown
                e.printStackTrace();
            }
            try {
                mifare.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // Generate NdefMessage to be written onto the tag
            NdefMessage msg = null;
            try {
                NdefRecord r1 = NdefRecord.createMime("text/plain", message.getBytes("UTF-8"));
                NdefRecord r2 = NdefRecord.createApplicationRecord("com.example.myname.myapplication");
                msg = new NdefMessage(r1, r2);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            // Generate Ndef object from tag object
            Ndef ndef = Ndef.get(tag);

            // Connect NDEF, write message and close connection
            try {
                ndef.connect();
                ndef.writeNdefMessage(msg);
                ndef.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (FormatException e) {
                e.printStackTrace();
            } catch (Exception e) {
                //Trying to catch any exception that may be thrown
                e.printStackTrace();
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    btn.setImageResource(R.drawable.arrow_red);
                    tv.setText("");
                }
            });
            curAction = "handle";
        }
    })).start();
}

EDIT: I don't know if something was wrong with Android Studio yesterday or if your solution actually changed the situation, but I updated the code and now get the following exception:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
                       Process: com.example.alex.nfcapppce, PID: 25918
                       java.lang.IllegalStateException: Close other technology first!
                           at android.nfc.Tag.setConnectedTechnology(Tag.java:458)
                           at android.nfc.tech.BasicTagTechnology.connect(BasicTagTechnology.java:78)
                           at android.nfc.tech.Ndef.connect(Ndef.java)
                           at com.example.alex.nfcapppce.MainActivity$2.run(MainActivity.java:194) //The line saying ndef.connect()
                           at java.lang.Thread.run(Thread.java:761)

I don't quite understand why this happpens, because first I connect the mifare, wait until it's connected, do my transceiving, close my mifare and after that the block with ndef.connect() is called. Does this mean somewhere in my transceiving block I get an Exception, therefore I'm not closing the mifare correctly and cannot open the ndef? That would be weird as I am not getting an exception even though I swapped out the IOException with just Exception so I catch every exception no matter the exact type.

EDIT 2: I now get why the application is ending in this exception. The code actually works and my tag is now protected with the password, when I try to use the same tag again I dont authenticate first so the transceive fails, leading to a breaking of the try-catch block that would also contain the close function. I solved this by making the MifareUltralight object available in the whole Thread and closing it before running the ndef.connect()'s section.

Now my (hopefully) last question is: Can I authenticate using the Ndef class? My Ndef object doesnt seem to have an authenticate method, so I would have to use MifareUltralight for this again. But when I close the MifareUltralight connection for opening the Ndef connection is the authentication not lost? Or is my only possibility to write Ndef messages on a password protected tag using Strings, cutting them into 4-byte pages and writing them one after the other using MifareUltralight.writepage(byte[] addr, byte[] data)? When I use the updated above I get an IOException from ndef.writeNdefMessage(), I guess this means closing the mifare connection also unauth'd me.

Thanks in advance.


回答1:


You never connect to the tag when using the MifareUltralight technology. Consequently, calling mifare.transceive() will result in an exception. Your app crashes because this exception is probably not an instance of IOException (which you would have caught in your code).

Therefore, make sure to call

mifare.connect();

before you transceive any commands and also make sure to close the instance again after that:

try {
    mifare.close();
} catch (Exception ignored) {}


来源:https://stackoverflow.com/questions/45477331/setting-ntag213-password-in-android-with-mifareultralight-transceive-crashes-no

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!