pokusew / nfc-pcsc

Easy reading and writing NFC tags and cards in Node.js
MIT License
535 stars 132 forks source link

Error when writing data. Receives an Invalid data length error. #133

Closed TommyLiang1 closed 2 years ago

TommyLiang1 commented 2 years ago

Hi @pokusew.

I am testing my NFC card reader through the command npm run example. I am running into an issue when writing to a MiFare Classic 1K card. I was following issue #25 as I received a "Write operation failed: Status code: 0x6300" error at first.

After passing in the 3rd parameter for the reader.write() function so that it looks like this await reader.write(4, data, 16);, I received an "Invalid data length" error.

This is the if statement that returns that error image I added a console.log line to print the values of data.length, blockSize and data.length%blockSize. It returns 4, 16, 4 respectively. Since the data.length is 4 and blockSize is 16, the if statement conditions will be met and will give an "Invalid data length" error as I stated.

Why is this the case? Why is data.length returning 4(I'm assuming that it should return multiples of 16 in order to bypass that if statement)?

I tried commenting out the if statement and the last line in the image below replaced the error. image I know that this is wrong as the very next if condition won't run as data.length is not greater than blockSize which is why I made this issue.

Environment Information: OS: Ubuntu 20.04 Node Version: 16.16.0 NPM Version: 8.11.0 Card Reader: ACR122U

pokusew commented 2 years ago

Hi @TommyLiang1,

Thank you for posting your issue here. 👍

It looks like you are passing data of an invalid length.

The data.length must always be a non-zero multiple of the blockSize, i.e. you can always write only whole data blocks.

In the case of MIFARE Classic, the blockSize is 16 bytes. That means you can write only 16 bytes, 32 bytes, 48 bytes, etc.

Also, be cautious when writing more than one block of data (i.e. more than 16 bytes). In each sector of MIFARE Classic, there are 4 blocks – 3 data blocks and 1 sector trailer (the last block). When you use reader.write it will automatically perform the required number of write operations while increasing the block number. That may cause an inadvertent overwrite of a sector trailer. It is always best to use reader.write to write only 16 bytes (one block) at a time.

You can find more details in the MIFARE Classic example here.

Let me know if it's clear now or if you need any more help. 🙂


PS Don't forget to star ⭐️ my library if you find it useful. 😃 Thanks.

TommyLiang1 commented 2 years ago

Hi @pokusew, Thank you for your quick response.

After reading your comment, I traced back to where the data variable is initialized.

It is through this line const data = Buffer.allocUnsafe(4).fill(0); where the data variable is initialized before the reader.write() function is called.

I changed the 4 to 16 in ...Buffer.allocUnsafe(16)... and it works.

Is this an appropriate fix?

pokusew commented 2 years ago

@TommyLiang1, Yes, it is (I assume you are talking about line 75 in read-write.js example).

BTW, you can look directly at the mifare-classic.js example where it is already set up correctly for MIFARE Classic (you can use npm run example-mifare-classic to run it).

Hope it helps. 🙂


PS Don't forget to star ⭐️ my library if you find it useful. 😃 Thanks.