Giter Club home page Giter Club logo

Comments (6)

bierlair avatar bierlair commented on September 2, 2024 1

Everything works as expected. With this I was actually able to break it down even further.
I would like to detect which kind of NTAG chip I am using, as they all come with different pages for storing passwords and configs.

Here is something quick and dirty that helps identify the NTAG chip. Next step would be to return the appropriate offsets in an object property, such as model.offset = 123

	async getModel(reader) {

		try {

			let cmd = Buffer.from([
				0xFF, // Class
				0x00, // Direct Transmit (see ACR122U)
				0x00, // ...
				0x00, // ...
				0x03, // Length of Direct Transmit payload
				0xd4, // Data Exchange Command (see PN533 docs)
				0x42, // inserted
				0x60, // GET_VERSION
			]);

			let response = await reader.transmit(cmd, 13);

			// console.log('+--- Vendor    :', response[4]);
			// console.log('+--- Type      :', response[5]);
			// console.log('+--- SubType   :', response[6]);
			// console.log('+--- Version 0 :', response[7]);
			// console.log('+--- Version 1 :', response[8]);
			// console.log('+--- Storage   :', response[9]);

			let model = {};
			model.name = null;
			model.page = null;

			if(response[4] === 4 && response[5] === 4) {
				if(response[6] === 1 && response[7] === 1 && response[8] === 0 && response[9] === 11) {
					model.name = "NTAG210";
				} else if(response[6] === 1 && response[7] === 1 && response[8] === 0 && response[9] === 14) {
					model.name = "NTAG212";
				} else if(response[6] === 2 && response[7] === 1 && response[8] === 0 && response[9] === 15) {
					model.name = "NTAG213";
				} else if(response[6] === 4 && response[7] === 1 && response[8] === 0 && response[9] === 15) {
					model.name = "NTAG213F";
				} else if(response[6] === 2 && response[7] === 1 && response[8] === 0 && response[9] === 17) {
					model.name = "NTAG215";
				} else if(response[6] === 2 && response[7] === 1 && response[8] === 0 && response[9] === 19) {
					model.name = "NTAG216";
				} else if(response[6] === 4 && response[7] === 1 && response[8] === 0 && response[9] === 19) {
					model.name = "NTAG216F";
				}
			}
			return model;

		} catch (err) {
			console.error('get_version error', err);
		}

Reference guide for this:

// get version
> FF 00 00 00 03 D4 42 60
// response
< D5 43 00 00 04 04 02 01 00 13 03 90 00


Details:

            Vendor (04 = NXP)
            |
D5 43 00 00 04   04    02        01   00      13    03 90 00
                 |      |         |   |       |
+------------+------+---------+-----------+--------------+
| Chip       | Type | Subtype | Version   | Storage size |
+------------+------+---------+-----------+--------------+
| NTAG210    | 0x04 | 0x01    | 0x01 0x00 | 0x0B         |
| NTAG212    | 0x04 | 0x01    | 0x01 0x00 | 0x0E         |
| NTAG213    | 0x04 | 0x02    | 0x01 0x00 | 0x0F         |
| NTAG213F   | 0x04 | 0x04    | 0x01 0x00 | 0x0F         |
| NTAG215    | 0x04 | 0x02    | 0x01 0x00 | 0x11         |
| NTAG216    | 0x04 | 0x02    | 0x01 0x00 | 0x13         |
| NTAG216F   | 0x04 | 0x04    | 0x01 0x00 | 0x13         |
+------------+------+---------+-----------+--------------+
| NT3H1101   | 0x04 | 0x02    | 0x01 0x01 | 0x13         |
| NT3H1101W0 | 0x04 | 0x05    | 0x02 0x01 | 0x13         |
| NT3H2111W0 | 0x04 | 0x05    | 0x02 0x02 | 0x13         |
| NT3H2101   | 0x04 | 0x02    | 0x01 0x01 | 0x15         |
| NT3H1201W0 | 0x04 | 0x05    | 0x02 0x01 | 0x15         |
| NT3H2211W0 | 0x04 | 0x05    | 0x02 0x02 | 0x15         |
+------------+------+---------+-----------+--------------+
| MF0UL1101  | 0x03 | 0x01    | 0x01 0x00 | 0x0B         |
| MF0ULH1101 | 0x03 | 0x02    | 0x01 0x00 | 0x0B         |
| MF0UL2101  | 0x03 | 0x01    | 0x01 0x00 | 0x0E         |
| MF0ULH2101 | 0x03 | 0x02    | 0x01 0x00 | 0x0E         |
+------------+------+---------+-----------+--------------+

==> NTAG Technical Doc, Table 28

And yes, NFC technical guides are tough to dig through. So good code examples would help beginners to kick off faster.

Cheers :-)

from nfc-pcsc.

pokusew avatar pokusew commented on September 2, 2024

Hi @bierlair,

thank you for posting your issue here.

According to the official documentation, it is possible to protect NTAG21x cards with password.
To read/write (based on your card's access config) password protected cards, you need to authenticate using PWD_AUTH command first.

And all these things should be doable using ACR122U and nfc-pcsc library. 😃

I don't know, where the problem might be. Could you please answer the following questions so that we can find why it doesn't work?

  1. What operating system, what reader, and card (I suppose NTAG21x) do you use?

  2. Are you able to read unprotected NTAG21x card?

  3. What's the content of pwdResponse? Can you log it and send it here?
    pwdResponse response should look like the following (7 bytes):

    d5 43 00 XX XX 90 00
    byte 0: d5 prefix for response of Data Exchange Command (see PN533 docs)
    byte 1: 43 prefix for response of Data Exchange Command (see PN533 docs)
    byte 2: Data Exchange Command Status 0x00 is success (see PN533 docs)
    bytes 3-4: Data Exchange Command Response – PACK (2 bytes password acknowledgment) from card
    bytes 5-6: ACR122U success code
    

    Note about PACK: You can change the value. It is stored in the last configuration page of the card, see the docs (8.5 Memory organization)

  4. Just for sure: Make sure you authenticate and read data from card in the same session. You have to authenticate the card every time you attach it.

Hope it helps. 🙂

Looking forward to your reply. I believe we make it work together. 🙂


To be honest, I have never tried to access protected cards before. I don't have any experience with NTAG21x cards (only with Mifare Ultralight EV1, Classic, and DESFire EV1).

Fortunately, according to the documentation, I have been able to make it work on Mifare Ultralight EV1 (it is very similar to NTAG21x cards, it even uses same commands). After I issue PWD_AUTH command, I am able to read the (password-read-protected) memory. 🚀

Here is my code to authenticate card:

reader.on('card', async card => {

  console.log('card detected', card);

  // PASSWORD (4 bytes) (stored on card in page 18)
  const password = Buffer.from([
    0xff,
    0xff,
    0xff,
    0xff,
  ]);

  // PACK (2 bytes) (stored in page 19 as first two bytes)
  // PACK is the response from card in case of successful PWD_AUTH cmd
  const pack = Buffer.from([
    0xab,
    0xcd
  ]);

  try {

    // CMD: PWD_AUTH via Direct Transmit (ACR122U) and Data Exchange (PN533)
    const cmd = Buffer.from([
      0xFF, // Class
      0x00, // Direct Transmit (see ACR122U)
      0x00, // ...
      0x00, // ...
      0x07, // Length of Direct Transmit payload
      // Payload (7 bytes)
      0xd4, // Data Exchange Command (see PN533 docs)
      0x42, // inserted
      0x1b, // PWD_AUTH
      ...password,
    ]);

    console.log('pwd_auth cmd', cmd);

    const response = await reader.transmit(cmd, 7);

    console.log('pwd_auth response', response);
    // pwd_auth response should look like the following (7 bytes)
    // d5 43 00 ab cd 90 00
    // byte 0: d5 prefix for response of Data Exchange Command (see PN533 docs)
    // byte 1: 43 prefix for response of Data Exchange Command (see PN533 docs)
    // byte 2: Data Exchange Command Status 0x00 is success (see PN533 docs)
    // bytes 3-4: Data Exchange Command Response – our PACK (set on card in page 19, in bytes 0-1) from card
    // bytes 5-6: ACR122U success code


  } catch (err) {
    console.error('pwd_auth error', err);
    return;
  }

});

That's how I set up the password protection (don't allow to read content without authentication):

reader.on('card', async card => {

  try {

    // set custom PASSWORD (4 bytes) (stored in page 18)
    await reader.write(19, password);

    // set custom PACK (2 bytes) (stored in page 19 as first two bytes)
    const packPage = await reader.read(19, 4);
    packPage[0] = pack[0];
    packPage[1] = pack[1];
    await reader.write(19, packPage);

    // read current configuration
    const config = await reader.read(16, 8);

    // Configuration page 16
    console.log(config[0]);
    console.log(config[1]);
    console.log(config[2]);
    console.log(config[3]); // AUTH0 (default: 0xff)

    // Configuration page 17
    console.log(config[4]); // ACCESS
    console.log(config[5]); // VCTID (default: 0x05)
    console.log(config[6]);
    console.log(config[7]);

    // Protect everything (start with first data page)
    config[3] = 0x04;

    // set ACCESS bits
    // bit 7: PROT One bit inside the ACCESS byte defining the memory protection
    //          0b ... write access is protected by the password verification
    //          1b ... read and write access is protected by the password verification
    // bit 6: CFGLCK Write locking bit for the user configuration
    //        - 0b ... user configuration open to write access
    //        - 1b ... user configuration permanently locked against write access
    // bits 5-3: reserved
    // bits 2-0: AUTHLIM
    // bit number-76543210
    //            ||||||||
    config[4] = 0b10000000;

    // set custom access rules
    await reader.write(16, config);

  } catch (err) {
    console.error(err);
  }

});

from nfc-pcsc.

bierlair avatar bierlair commented on September 2, 2024

Awesome, this is exactly what I needed.
I was pretty close to completing this myself by reading the technical docs of NTAG21x, but your code snippet accelerated things.

Since I am working with NTAG216, I needed to adjust the page addresses.

The try/catch block for setting the password now looks something like this:

try {

	// set custom PASSWORD (4 bytes) (stored in page 229)
	await reader.write(229, password);

	// set custom PACK (2 bytes) (stored in page 230 as first two bytes)
	const packPage = await reader.read(230, 4);
	packPage[0] = pack[0];
	packPage[1] = pack[1];
	await reader.write(230, packPage);

	// read current configuration
	const config = await reader.read(227, 8);

	// Configuration page 16
	console.log(config[0]);
	console.log(config[1]);
	console.log(config[2]);
	console.log(config[3]); // AUTH0 (default: 0xff)

	// Configuration page 17
	console.log(config[4]); // ACCESS
	console.log(config[5]); // VCTID (default: 0x05)
	console.log(config[6]);
	console.log(config[7]);

	// Protect everything (start with first data page)
	config[3] = 0x04;

	// set ACCESS bits
	// bit 7: PROT One bit inside the ACCESS byte defining the memory protection
	//          0b ... write access is protected by the password verification
	//          1b ... read and write access is protected by the password verification
	// bit 6: CFGLCK Write locking bit for the user configuration
	//        - 0b ... user configuration open to write access
	//        - 1b ... user configuration permanently locked against write access
	// bits 5-3: reserved
	// bits 2-0: AUTHLIM
	// bit number-76543210
	//            ||||||||
	config[4] = 0b10000000;

	// set custom access rules
	await reader.write(227, config);

} catch (err) {
	console.error(err);
}

Thanks again 👍

from nfc-pcsc.

pokusew avatar pokusew commented on September 2, 2024

@bierlair That's great. 👍

So everything works as expected? Can we close the issue?

BTW I think, it would be useful to have this in the examples. Thank you very much for pointing it out to me. In future, the examples should explain the basic usage and commands of the most popular cards and tags to help people to get started easily. From my experience, I can say, that regarding NFC standards and cards, there is a lack of documentation (or it is poor, hard to find and understand, especially for beginners).


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

from nfc-pcsc.

lokachun avatar lokachun commented on September 2, 2024

@pokusew Hello, I am currently using ACS ACR 1252 1S CL Reader PICC 0 for my Mifare Ultralight. I wish to add a password to my tag so that others can write on it if they enter the password. Could I know what platform are you guys using to code and link with the reader because I am unable to find it. Thank you!

from nfc-pcsc.

dcr31000 avatar dcr31000 commented on September 2, 2024

Hello, I want to add a password protection after writing data on NTAG216. I tried @bierlair code sample but the last writing command break my nfc cards...

This in my code:

// PASSWORD (4 bytes) (stored on card in page 18)
const CARD_PASSWORD = Buffer.from([
    0xff,
    0xff,
    0xff,
    0xff,
]);

// PACK (2 bytes) (stored in page 19 as first two bytes)
// PACK is the response from card in case of successful PWD_AUTH cmd
const PACK = Buffer.from([
	0xab,
	0xcd
]);

// set custom PASSWORD (4 bytes) (stored in page 229)
await reader.write(229, CARD_PASSWORD);

// set custom PACK (2 bytes) (stored in page 230 as first two bytes)
const packPage = await reader.read(230, 4);
packPage[0] = PACK[0];
packPage[1] = PACK[1];
await reader.write(230, packPage);

const config = await reader.read(227, 8);
config[3] = 0x04;
config[4] = 0b10000000;

await reader.write(227, config);

Could you please help me to find a solution ? Thanks all

from nfc-pcsc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.