revtel / react-native-nfc-manager

React Native NFC module for Android & iOS
MIT License
1.33k stars 317 forks source link

MiFare card scan #554

Closed deepakkumardk closed 1 year ago

deepakkumardk commented 1 year ago

Thanks for this great library. I do have a question, does this library support MiFare classic cards values for DEC, RDEC, HEX, RHEX

I am not getting the payload in the logs for MiFare card, is this the expected behaviour.

{"techTypes":["android.nfc.tech.NfcA","android.nfc.tech.MifareClassic","android.nfc.tech.NdefFormatable"],"id":"XXXXXXXX"}

gshoanganh commented 1 year ago

mine is the same. No one has solved this problem. {"techTypes":["android.nfc.tech.NfcA","android.nfc.tech.MifareClassic","android.nfc.tech.NdefFormatable"],"id":"NNNNNN"}

Sachin926 commented 1 year ago

Hi @whitedogg13 as far as my findings go, the leading cause of the issue is the fact that MiFARE classic cards require authentication before they can be read or written. According to the datasheet of MiFARE classic provided by NXP, to read the nuid we need to extract the first four bytes from block 0 of sector 0, from which the main code could be extracted.

Additionally, one easy way would be to extract the bytes array by extracting the data from the ID string itself that we are getting as of now, passing your string ID inside the method would get you the required byte array. This code would work as by default the first four bytes from block 0 of sector 0 can be read from the ID that is being received inside the tag data.

formatMiFareTagID = (id) => {
    const hexArray = id.match(/.{1,2}/g)
    const byteArray = hexArray.map((item) => parseInt(item, 16))
    return byteArray
  }

FYI @deepakkumardk @gshoanganh

gshoanganh commented 1 year ago

@Sachin926 this is the result i got (attached). myapp but the required value of the card is a string of numbers. is there a way to convert to text to get?

i use this function:

byteToHexString = (bytes) =>{
if(!Array.isArray(bytes) || !bytes.length) return '';
let result = '';
for (let i = 0; i < bytes.length; i++){
   result += `0${bytes[i].toString(16)}`.slice(-2);
}
return result;
}

but the result is not correct.

Sachin926 commented 1 year ago

@gshoanganh I guess with this id you must be getting [ 205, 31, 80, 170 ] from the method that I provided earlier, this is what the nuid of your card is and if you look at the first four elements of the expected result array they are exactly same.

Now speaking of getting the entire result array I guess you have no other choice but to read the entire data from block 0 of sector 0 and as I've already stated these cards require authentication before they can be read.

Fortunately, a fresh MiFare classic card comes with a default key that can be used to read or write the data.

as far as I remember key A = 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF.

use this key to access your MiFare card and then read the block 0 of sector 0 you'll have your result, but keep in mind the docs of react-native-nfc-manager. Additionally, you can check the Datasheet of MiFare classic card provided by NXP. Refer to the bottom of page number 8, you'll get what you need I hope.

gshoanganh commented 1 year ago

hi boy, @Sachin926 I tried to the authentication with KeyA as you requested, but it doesn't seem to be correct. The value of my card is: 014300. (correct) important: Do you have any way to get the data of block 1 of sector 1?. i tried NfcManager.mifareClassicHandlerAndroid.mifareClassicAuthenticateA(1, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]) but no success!

my code:

NfcManager.registerTagEvent(tag => console.log(tag))
            .then(() => NfcManager.requestTechnology(NfcTech.MifareClassic))
            .then(() => NfcManager.getTag())
            .then(tag => {

                this.setState({ tag })
                return NfcManager.mifareClassicHandlerAndroid.mifareClassicGetSectorCount()
            })
            .then(sectorCount => {

                this.setState({ sectorCount });
            }).then(async () => {

                return await NfcManager.mifareClassicHandlerAndroid // STEP 2
                    .mifareClassicAuthenticateA(0, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF])
            }).then(async (temp) => {
                NfcManager.mifareClassicHandlerAndroid
                    .mifareClassicSectorToBlock(0).then((sectorToBlock) => {
                        this.setState({ sectorToBlock })
                        NfcManager.mifareClassicHandlerAndroid.mifareClassicReadBlock(sectorToBlock)
                            .then(data => {
                                let hex = this.byteToHexString(data)
                                this.setState({ result: data, hex, temp })

                                NfcManager.ndefFormatableHandlerAndroid.formatNdef(data, true)
                                    .then((hand) => {
                                        this.setState({ hand })
                                    })
                                //const resp = await NfcManager.nfcVHandler.transceive(payload);

                                // const parsedText = ByteParser.byteToString(data);
                                // this.setState({ firstBlockInSector: parsedText });
                            })
                    }).catch((err) => {

                        this.setState({ error: err })
                    })
            })
            .catch((error) => {
                this.setState({ error: 'err-t: ' + error })
            })
            .finally(() => {

                NfcManager.cancelTechnologyRequest();
                this._stopDetection() 
            });
    }

their tool on CH Play: screen

gshoanganh commented 1 year ago

thanks for your support, i have re-read the document you sent me, and i solved!!!!. page 8-9

angel-christian25 commented 1 year ago

@gshoanganh can you please share the working code for read and write? Thanks

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] commented 1 year ago

This issue was closed because it has been stalled for 5 days with no activity.