Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transmit example #57

Closed
JohnMcLear opened this issue Dec 19, 2018 · 4 comments
Closed

Transmit example #57

JohnMcLear opened this issue Dec 19, 2018 · 4 comments
Assignees
Labels

Comments

@JohnMcLear
Copy link
Contributor

JohnMcLear commented Dec 19, 2018

Hey man, thanks for all the hard work on this project :)

I'm working on some logic which can get the SEID from an IC using an APDU. Pretty simple stuff I have working on other platforms (Cordova etc.) but I seem to struggling with this project. It's likely I'm a bit rusty as I haven't worked on it for a few years so apology if this is user error however I have read through the docs and do feel like the transmit method docs could do with some additional input (of which I will be happy to do once I am comfortable with the method).

The following:

nfc.on('reader', reader => {
  reader.autoProcessing = false; // Required else you won't get here..

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

    // APDU Transmit logic
    console.log("card detected");
    const apdu = "80CA9F7F2C"; // Perhaps I should be providing this as hex array then converting to Buffer?
    var buf = Buffer.from(apdu, 'utf8'); // Maybe this should be hex?

    try{
      let uid = await reader.transmit(buf, 12); // Tried different buffer length values.
      console.log("UID", uid.toString('hex')); // UID / SEID value is wrong.  It should be 16 chars or so but we only get 4...
    }catch(err){
      console.log(err); // No error is thrown :)
    }
...

Returns:

...
card inserted <Buffer 3b 8e 80 01 80 31 80 66 b1 84 0c 01 6e 01 83 00 90 00 1c>
trying to connect CONNECT_MODE_CARD 2
connected { type: 2, protocol: 2 }
card detected
transmitting <Buffer 38 30 43 41 39 46 37 46 32 43> 12
UID 6e00
status { state: 4063250, atr: <Buffer > }
changes 196656
card removed
trying to disconnect { type: 2, protocol: 2 }
disconnected

The UID value should be much longer.

I'm 99% correct the APDU is correct.

I'm only making assumptions I'm doing transmit correctly.

I think the error lies in the format I'm encoding the APDU (from string to Buffer?)

@pokusew pokusew changed the title transmit example Transmit example Dec 19, 2018
@pokusew pokusew self-assigned this Dec 19, 2018
@pokusew
Copy link
Owner

pokusew commented Dec 20, 2018

Hi @JohnMcLear,

thank you for posting your issue here. 🙂

Firstly, I am sorry that the API is not documented better. Will improve, I promise. 😉
At the moment, only examples are provided. Whenever you doubt about the usage of the method, I recommend looking directly into the source code, which should clarify it.

The reader.transmit(data, responseMaxLength) method accepts two arguments:

  1. data – a Buffer instance containing the data (bytes) to transmit
  2. responseMaxLength – an integer specifying the maximum length (in bytes) of the expected response
    In case you specify too small value and the response exceeds the given maximum length, it gets truncated the transmit fails and an error is thrown. If you specify much bigger value than needed, nothing happens – but don't do that for performance reasons.

So your usage of the method is correct. But you are passing the bad data.

The correct way of constructing the data with your APDU is following:
80CA9F7F2C is actually a HEX representation of 5 bytes. Each two-digits specify one byte.

So you create the Buffer from that like this:

// creating a Buffer instance from a hex string
// letters can be lowercase or uppercase – it doesn't matter
const data = Buffer.from('80CA9F7F2C', 'hex'); // <- note the 'hex' encoding

or like this:

// creating a Buffer instance from an array of bytes
// Note about the number literals:
//   0x prefix says the number is in hexadecimal representation
//   0b prefix says the number is in binary representation (0 and 1 for each bit)
//   0x80 = 128 = 0b10000000
const data = Buffer.from([
    0x80,
    0xca, // letters can be lowercase or uppercase – it doesn't matter
    0x9f,
    0x7f,
    0x2c,
]);

So your code after the updates could look like:

nfc.on('reader', reader => {

    reader.autoProcessing = false;
    // this turns off auto processing
    // by default (when autoProcessing is set to true) when a card is detected
    // an APDU command is automatically transmitted to obtain the card's UID
    // then in card event, card.uid is available
    // it works well ONLY for standard ISO 14443-3 tags like NTAG or Mifare Ultralight

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

        // APDU Transmit logic
        console.log('card detected');
        const apdu = '80ca9f7f2c';
        const data = Buffer.from(apdu, 'hex');

        try {
            const uid = await reader.transmit(data, 12); // 12 bytes = 24 hex digits (update according to your needs)
            console.log(`UID`, uid.toString('hex'));
        } catch (err) {
            console.log(err);
        }
        
    });

});

Hope I clarified a few things a bit. Please let me know if you are able to make it work. 🙂


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

@JohnMcLear
Copy link
Contributor Author

Excellent thanks for this :) I tried the above logic (copy/pasted) and I get thsi output:

status { state: 4915234,
  atr: <Buffer 3b 8e 80 01 80 31 80 66 b1 84 0c 01 6e 01 83 00 90 00 1c> }
changes 65584
card inserted <Buffer 3b 8e 80 01 80 31 80 66 b1 84 0c 01 6e 01 83 00 90 00 1c>
trying to connect CONNECT_MODE_CARD 2
connected { type: 2, protocol: 2 }
card detected
transmitting <Buffer 80 ca 9f 7f 2c> 12
{ TransmitError: An error occurred while transmitting.
    at reader.transmit (/home/jose/node_modules/nfc-pcsc/dist/Reader.js:275:20)
  name: 'TransmitError',
  code: 'failure',
  previous: Error: SCardTransmit error: Insufficient buffer.(0x80100008) }
status { state: 4980754, atr: <Buffer > }
changes 458800
card removed
trying to disconnect { type: 2, protocol: 2 }
disconnected

To fix I bumped the buffer length value up to 47.

Entire code is now this:

"use strict";

// #############
// Logs cards' uid
// #############

const { NFC, TAG_ISO_14443_3, TAG_ISO_14443_4, KEY_TYPE_A, KEY_TYPE_B } = require('nfc-pcsc');

// minilogger for debugging
//
function log() {
  console.log(...arguments);
}

const minilogger = {
  log: log,
  debug: log,
  info: log,
  warn: log,
  error: log
};

const nfc = new NFC(minilogger);

nfc.on('reader', reader => {

        reader.autoProcessing = false;

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

                // APDU Transmit logic
                console.log('card detected');
                const apdu = '80ca9f7f2c';
                const data = Buffer.from(apdu, 'hex');

                try {
                    const uid = await reader.transmit(data, 47); // 12 bytes = 24 hex digits (update according to your needs)
                    console.log(`UID`, uid.toString('hex'));
                } catch (err) {
                    console.log(err);
                }

        });


        reader.on('error', err => {
                console.error('reader error', err);
        });

        reader.on('end', () => {
                console.log(reader.name + ' reader disconnected.');
        });


});

nfc.on('error', err => {
        console.error(err);
});

Any idea why 47 is the magic number here? Does that come from the response and is it something I should know the length based on a response?

@pokusew
Copy link
Owner

pokusew commented Dec 31, 2018

Hi @JohnMcLear,

sorry for the late reply. It's great you made it work. 🙂

Unfortunately, it seems my previous statement about the responseMaxLength was incorrect. 😄
The correct version is (I already updated my previous comment):
In case you specify too small value and the response exceeds the given maximum length, it gets truncated the transmit fails and an error is thrown.

The reader (reps. the card) is returning 47 bytes as the response to the 80 ca 9f 7f 2c command. That's the reason you have to set the second argument – the expected responseMaxLength – of the reader.transmit method to 47 or bigger.

You should know the expected response length of any command you use. You should find that value in the appropriate documentation. Could you please add a link to the documentation of the command you used? Or link to the docs of the card you use?

Anyway, does it work for you? Did you manage to get response you wanted?

If so, feel free to close the issue.

Hope it helps. 🙂

@JohnMcLear
Copy link
Contributor Author

Ack, yeah all working fine :)

Thanks! :)

@pokusew pokusew closed this as completed Jan 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants