Write to specified sector on tag using react-native-nfc-manager - nfc

I'm using an NTAG I2C plus 2k memory tag and using the react-native-nfc-manager library to interface with the tag.
Is there a way to specify the sector that you're intending to write to?
I know there is an API to specify the page offset to write to, but how do you specify the sector the page offsets are in?
(Updated to include below code sample)
let tech = Platform.OS === 'ios' ? NfcTech.MifareIOS : NfcTech.NfcA;
await NfcManager.requestTechnology(tech, {
alertMessage: 'Hold your phone close to the NFC tag.',
});
let fullLength = data.length + 7;
let payloadLength = data.length + 3;
let cmd =
Platform.OS === 'ios'
? NfcManager.sendMifareCommandIOS
: NfcManager.transceive;
// select sector 2 prior to writing data
await cmd([0xc2, 0xff]);
await cmd([0x02, 0x00, 0x00, 0x00]);
await cmd([
0xa2,
MEMORY_MAPPING[`${chunkToWriteTo}`][1],
0x03,
fullLength,
0xd1,
0x01,
]);
await cmd([
0xa2,
MEMORY_MAPPING[`${chunkToWriteTo}`][2],
payloadLength,
0x54,
0x02,
0x65,
]);
let currentPage = MEMORY_MAPPING[`${chunkToWriteTo}`][0] + 2;
let currentPayload = [0xa2, currentPage, 0x6e];
for (let i = 0; i < data.length; i++) {
currentPayload.push(parseInt(data[i]));
if (currentPayload.length == 6) {
try {
await cmd(currentPayload);
} catch (error) {
console.log(error);
}
currentPage += 1;
currentPayload = [0xa2, currentPage];
}
}
Thanks in advance.

So "NTAG I2C plus 2k" seems to be a Certified Type 2 tag using NfcA comms.
It's datasheet
This Tag has additional commands over the Type 2 Standard to select the sector because Type 2 Tag's don't normally have Sectors.
So reading the datasheet Section 10.12 you would transceive the following commands bytes an example
C2h FFh - Select Sector
03h 00h 00h 00h - Sector 3
Then write to page address as normal with the A2h command byte
react-native-nfc-manage offers an nfcAHandler with a transceive method to send and receive these low level commands to the NFC chip.
Update:
For iOS it treats Type 2 Tags as Mifare Ultralight's and thus sendMifareCommandIOS from the API to send the same commands.
(Both Android and iOS have the nfcAHandler)
Note I've not tried this, I just do things with normal Type 2 Tags

Related

How to differentiate between devices in the windows HID API?

I need to detect when a gamepad is plugged in for my game (I'm not using a higher-level input API for reasons), how can I do this? I've already enumerated all HID devices and opened files on them (except keyboard, mouse ofc) and can get all the info on the device, but what info do I want? What value(s) will tell me right away that this is an xbox controller, for example, and where are these values?
My code for enumerating over the devices (very messy atm :p):
DWORD required_size = 0, determined_size;
SP_DEVICE_INTERFACE_DATA device_interface_data;
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
PSP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data;
HANDLE current_device;
PHIDP_PREPARSED_DATA preparsed_data;
WCHAR product_string[128];
for (int i = 0; ; ++i) /* Enumerate HID devices */
{
rv = SetupDiEnumDeviceInterfaces(device_enumeration, NULL, &interface_guid, i, &device_interface_data); /* Does the actual enumeration,
each time we increase index i
to get the next device */
error = GetLastError();
if (error == ERROR_NO_MORE_ITEMS) /* If there are no more devices, break */
break;
else if (!rv && error != ERROR_NO_MORE_ITEMS) /* Otherwise, we have a legit error */
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, NULL, 0, &required_size, NULL); /* Probing call only to get buffer size,
so error code (122) ignored */
/* Allocate new device detail struct using buffer size we obtained */
determined_size = required_size;
device_interface_detail_data = cr_safe_malloc(required_size);
device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
/* Get detailed info about device */
rv = SetupDiGetDeviceInterfaceDetail(device_enumeration, &device_interface_data, device_interface_detail_data, determined_size, &required_size, NULL);
if (!rv)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
cr_printf("FOUNDD DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
current_device = cr_open_device(device_interface_detail_data->DevicePath);
if (!current_device && GetLastError() == ERROR_ACCESS_DENIED)
goto Done;
cr_printf("OPENED DEVICE: %s\n\n", device_interface_detail_data->DevicePath);
preparsed_data = HidD_GetPreparsedData(current_device, &preparsed_data);
if (!preparsed_data)
{
cr_print_error(GetLastError());
return EXIT_FAILURE;
}
HidD_GetProductString(current_device, product_string, sizeof(product_string));
cr_printf("PRODUCT STRING: %S\n\n", product_string);
HidD_FreePreparsedData(&preparsed_data);
DeleteFile(device_interface_detail_data->DevicePath);
Done:
cr_safe_free(&device_interface_detail_data);
}
SetupDiDestroyDeviceInfoList(device_enumeration);
As you can see I've found the product string, which tells me what the device actually is, but maybe comparing product strings is not the best way to do PnP?
Check if the device ID contains "IG_". If it does, then it's an XInput device.
More info on that. But which device corresponds to which XInput dwUserIndex is more difficult question...
Also you can try to check for XUSB interface:
// {EC87F1E3-C13B-4100-B5F7-8B84D54260CB}
DEFINE_GUID(XUSB_INTERFACE_CLASS_GUID, 0xEC87F1E3, 0xC13B, 0x4100, 0xB5, 0xF7, 0x8B, 0x84, 0xD5, 0x42, 0x60, 0xCB);

Mifare cards: distinguish between 4-byte and 7-byte UIDs

I have a card reader that always report 64 bits, and can read cards with 4 or 7 byte UIDs.
As an example, I see it can report:
04-18-c5-82-00-00-00-00 - a 4-byte UID in the form uid0-uid1-uid2-uid3-00-00-00-00
04-18-c5-82-f1-3b-81-00 - a 7-byte UID in the form uid0-uid1-uid2-uid3-uid4-uid5-uid6-00
What prevents a 7-byte UID from having uid4, uid5 and uid6 set to zero? Is this covered in a spec? If so, which spec?
What prevents a 7-byte UID from having uid4, uid5 and uid6 set to zero?
Nothing. The format of the UID (as used by MIFARE cards) is defined in ISO/IEC 14443-3. Specifically for MIFARE cards, NXP has (or at least had?) some further allocation logic for 4 byte UIDs, but that's not publicly available.
Is it possible to distinguish the two cases?
If the reader outputs the UIDs exactly in the form that you showed in your example, then the answer is no (at least not reliably). However, some readers output the UID on 8 bytes and include the cascade tag for 7-byte-UIDs. Thus, all 7-byte-UIDs start with 0x88 for those readers. This does not seem to be the case with your reader.
Are there possible strategies to distinguish the two cases?
Some strategies come to my mind to distinguish 4-byte-UIDs from 7-byte-UIDs.
The first byte of a 7-byte-UID is the manufacturer code (as defined in ISO/IEC 7816-6 (see How to detect manufacturer from NFC tag using Android? on how to obtain the list). Thus, if you have a limited set of manufacturers (e.g. if you only use MIFARE cards with chips from NXP), you could interpret all UIDs that start with NXP's manufacturer code (0x04) as 7-byte-UIDs. Nevertheless, you should be aware that 4-byte-UIDs are allowed to start with 0x04 as well. Hence, this method is not 100% reliable and may fail for some cases.
The first byte of 4-byte-UIDs must not contain any of the following values: 'x8' (with x != '0'), 'xF'. If you find the first byte to match any of those values, you can assume the UID to consist of 7 bytes.
if you can get the ATQA response you can distinguish it. The lower byte of the ATQA shows you how long the UID is. (4/7/10Byte) As far as I know there is no other way to distinguish with 100% assurance
br
I know its bit late to the party, but for any one who is having the same doubt;
the documented way of creating a 7 Byte UID out of 4 Byte UID is in the Annex-6 of this pdf.
In case the page goes down, a shameless rip off from that page is given below.
Any and all mistakes if you find in the below code snippet rightfully belongs to NXP guys, not me.
But how do you know whether the tag is a 4 byte or 7 byte uid one?
From the ATQA response. Refer page 15/36 of the document 1 and page 8/15 of document 2 .
In case the document goes down, here is the relevant excerpt from the document 1.
The MF1S50yyX/V1 answers to a REQA or WUPA command with the ATQA value
shown in Table 11 and to a Select CL1 command (CL2 for the 7-byte UID variant) with the SAK value shown in Table 12.
Remark: The ATQA coding in bits 7 and 8 indicate the UID size according to ISO/IEC 14443 independent from the settings of the UID usage.
6. Annex, Source code to derive NUID out of a Double Size UID
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#define BYTE unsigned char
unsigned short UpdateCrc(unsigned char ch, unsigned short *lpwCrc)
{
ch = (ch^(unsigned char)((*lpwCrc) & 0x00FF));
ch = (ch^(ch<<4));
*lpwCrc = (*lpwCrc >> 8)^((unsigned short)ch << 8)^((unsigned
short)ch<<3)^((unsigned short)ch>>4);
return(*lpwCrc);
}
void ComputeCrc(unsigned short wCrcPreset, unsigned char *Data, int
Length, unsigned short &usCRC)
{
unsigned char chBlock;
do {
chBlock = *Data++;
UpdateCrc(chBlock, &wCrcPreset);
} while (--Length);
usCRC = wCrcPreset;
return;
}
void Convert7ByteUIDTo4ByteNUID(unsigned char *uc7ByteUID, unsigned char
*uc4ByteUID)
{
unsigned short CRCPreset = 0x6363;
unsigned short CRCCalculated = 0x0000;
ComputeCrc(CRCPreset, uc7ByteUID, 3,CRCCalculated);
uc4ByteUID[0] = (CRCCalculated >>8)&0xFF;//MSB
uc4ByteUID[1] = CRCCalculated &0xFF; //LSB
CRCPreset = CRCCalculated;
ComputeCrc(CRCPreset, uc7ByteUID+3, 4,CRCCalculated);
uc4ByteUID[2] = (CRCCalculated >>8)&0xFF;//MSB
uc4ByteUID[3] = CRCCalculated &0xFF; //LSB
uc4ByteUID[0] = uc4ByteUID[0]|0x0F;
uc4ByteUID[0] = uc4ByteUID[0]& 0xEF;
}
int main(void)
{
int i;
unsigned char uc7ByteUID[7] =
{0x04,0x18,0x3F,0x09,0x32,0x1B,0x85};//4F505D7D
unsigned char uc4ByteUID[4] = {0x00};
Convert7ByteUIDTo4ByteNUID(uc7ByteUID,uc4ByteUID);
printf("7-byte UID = ");
for(i = 0;i<7;i++)
printf("%02X",uc7ByteUID[i]);
printf("\t4-byte FNUID = ");
for(i = 0;i<4;i++)
printf("%02X",uc4ByteUID[i]);
getch();
return(0);
}
If you came here (as I did) to find a proper way to automatically get the UID from a card independent if it is a 4, 7 or 10 byte UID, I do it dynamically as following (found this logic somewhere on the internet but can't find it anymore to give proper credits. 10 Bytes not tested):
(this is C# code and is using winscard.dll under the hood):
public static UInt64 getCardUIDasUInt64() // *** only for mifare 1k cards ***
{
UInt64 UID = 0;
byte[] receivedUID = new byte[10]; // ***
Card.SCARD_IO_REQUEST request = new Card.SCARD_IO_REQUEST();
request.dwProtocol = (UInt32)Protocol; // *** use the detected protocol instead of statically assigned protocol type *** // Card.SCARD_PROTOCOL_T1;
request.cbPciLength = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Card.SCARD_IO_REQUEST));
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //get UID command for Mifare cards
//byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command for Mifare cards
int receivedBytesLength = receivedUID.Length;
int status = Card.SCardTransmit(hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref receivedBytesLength);
if (status == Card.SCARD_S_SUCCESS)
{
if (receivedBytesLength >= 2)
{
// do we have an error
if ((receivedUID[receivedBytesLength - 2] != 0x90) ||
(receivedUID[receivedBytesLength - 1] != 0x00))
{
throw new Exception(receivedUID[receivedBytesLength - 2].ToString());
}
else if (receivedBytesLength > 2)
{
for (UInt32 i = 0; i != receivedBytesLength - 2; i++)
{
UID <<= 8;
UID |= (UInt64)(receivedUID[i]);
};
}
}
else
{
throw new Exception(ResourceHandling.getTextResource("Error_Card_Read"));
}
}
return UID;
}
If you need the UID in hex, then use this (in addition to above code):
public static string getCardUIDasHex() // *** only for mifare 1k cards ***
{
UInt64 cardUID = getCardUIDasUInt64();
return string.Format("{0:X}", cardUID);
}
Maybe this is also of help to someone else as in the internet (also here in SO) there are many places which just read out the 1st four bytes of the UID which is just not correct anymore today.

Libnfc How to read NFC card content?

I'm trying to simply read an ISO 14443-2B ST SRx card content using ACR122 card reader.
I've set up my environment with Libnfc and the proper reader driver.
Right now I've managed to write a code that simply read the card UID and prints that out.
There's no documentation at all, and I totally don't know where to start for reading card content. Any clue or code snippet?
This is what I've done:
// To compile this simple example:
// $ gcc -o quick_start_example1 quick_start_example1.c -lnfc
// ./quick_start_example1
#include <stdlib.h>
#include <nfc/nfc.h>
void print_nfc_target(const nfc_target *pnt, bool verbose)
{
char *s;
str_nfc_target(&s, pnt, verbose);
printf("%s", s);
nfc_free(s);
}
int main(int argc, const char *argv[])
{
nfc_device *pnd;
nfc_target nt;
// Allocate only a pointer to nfc_context
nfc_context *context;
// Initialize libnfc and set the nfc_context
nfc_init(&context);
if (context == NULL) {
printf("Unable to init libnfc (malloc)\n");
exit(EXIT_FAILURE);
}
// Display libnfc version
const char *acLibnfcVersion = nfc_version();
(void)argc;
printf("%s uses libnfc %s\n", argv[0], acLibnfcVersion);
// Open, using the first available NFC device
pnd = nfc_open(context, NULL);
if (pnd == NULL) {
printf("ERROR: %s\n", "Unable to open NFC device.");
exit(EXIT_FAILURE);
}
// Set opened NFC device to initiator mode
if (nfc_initiator_init(pnd) < 0) {
nfc_perror(pnd, "nfc_initiator_init");
exit(EXIT_FAILURE);
}
printf("NFC reader: %s opened\n", nfc_device_get_name(pnd));
nfc_target ant[1];
nfc_modulation nm;
nm.nmt = NMT_ISO14443B;
nm.nbr = NBR_106;
nfc_initiator_list_passive_targets(pnd,nm,ant,1);
printf("%s\n",nfc_strerror(pnd)); // print Success
nfc_target ant2[1];
nfc_modulation nm2;
nm2.nmt = NMT_ISO14443B2SR;
nm2.nbr = NBR_106;
int res = 0;
int n = 0;
res = nfc_initiator_list_passive_targets(pnd, nm2, ant2, 1);
printf("%s\n",nfc_strerror(pnd)); // print Success
// printf("Cart identifier: %s\n", nt.nti.nsi.abtUID);
for (n = 0; n < res; n++) {
print_nfc_target(&ant2[n], true);
printf("\n");
}
// Close NFC device
nfc_close(pnd);
// Release the context
nfc_exit(context);
exit(EXIT_SUCCESS);
}
PS: I'm listing 2 times the targets because of a known bug ( http://www.libnfc.org/community/topic/1044/problem-with-init-of-iso14443b/ )
I wrote a small helper program to read ST SRx tags using LibNFC:
https://github.com/Depau/nfc-st-srx/
It still needs some changes to write them but it does read them successfully.
For a start (this is how I began), get EMV book 3 and read on the commands for card transactions, including the command APDUs and how they are written, response APDUs and how they are processed, response codes, status byte codes e.t.c. Then get books 1 - 5 to accompany the above book. Also get the book Implementing Electronic Card Payment Systems by Cristian Radu which will guide you through every step needed to learn how to develop EMV card applications. Hope that helps.

Core MIDI: when I send a MIDIPacketList using MIDISend() only the first packet is being sent

I am trying to send a MIDIPacketList containing two packets that describe controller position change message relating to a x-y style controller.
The function i'm trying to implement takes the an x and y position, and then creates the packets and sends them to the selected target device as follows:
- (void)matrixCtrlSetPosX:(int)posX PosY:()posY {
MIDIPacketList packetList;
packetList.numPackets = 2;
packetList.packet[0].length = 3;
packetList.packet[0].data[0] = 0xB0; // status: controller change
packetList.packet[0].data[1] = 0x32; // controller number 50
packetList.packet[0].data[2] = (Byte)posX; // value (x position)
packetList.packet[0].timeStamp = 0;
packetList.packet[1].length = 3;
packetList.packet[1].data[0] = 0xB0; // status: controller change
packetList.packet[1].data[1] = 0x33; // controller number 51
packetList.packet[1].data[2] = (Byte)posY; // value (y position)
packetList.packet[1].timeStamp = 0;
CheckError(MIDISend(_outputPort, _destinationEndpoint, &packetList), "Couldn't send MIDI packet list");
}
The problem I am having is that the program only appears to be sending out the first packet.
I have tried splitting the output into two separate MIDIPacketLists and two making two calls to MIDISend(), which does work, but I am sure that there must be something trivial I am missing out in building the midi packet list so that the two messages can be sent in one call to MIDISend(). I just cannot seem to figure out what the problem is here! Anyone here had experience doing this, or am I going about this the wrong way entirely?
Just declaring the MIDIPacketList doesn't allocate memory or set up the structure. There's a process to adding packets to the list. Here's a quick and dirty example:
- (void)matrixCtrlSetPosX:(int)posX PosY:(int)posY {
MIDITimeStamp timestamp = 0;
const ByteCount MESSAGELENGTH = 6;
Byte buffer[1024]; // storage space for MIDI Packets
MIDIPacketList *packetlist = (MIDIPacketList*)buffer;
MIDIPacket *currentpacket = MIDIPacketListInit(packetlist);
Byte msgs[MESSAGELENGTH] = {0xB0, 0x32, (Byte)posX, 0xB0, 0x33, (Byte)posY};
currentpacket = MIDIPacketListAdd(packetlist, sizeof(buffer),
currentpacket, timestamp, MESSAGELENGTH, msgs);
CheckError(MIDISend(_outputPort, _destinationEndpoint, packetlist), "Couldn't send MIDI packet list");
}
I adapted this code from testout.c found here

Access HKCU from TAPI Service Provider

I am writing an adapter TSP for a phone system. This system has a TAPI API but it is incompatible with the application I am trying to TAPI-enable. In order to place a call from the correct line, I need to know some information (from HKCU) about who is making the request. Since the TSP runs in the context of the Telephony service, I cannot access is directly. My plan was to use the functionality of LINE_CREATEDIALOGINSTANCE to read this information.
The problem I'm having is that the Telephony service is crashing immediately after returning from TUISPI_providerGenericDialog with the following stack trace:
72004400()
tapisrv.dll!_FreeDialogInstance#20() + 0xa93 bytes
tapisrv.dll!_ClientRequest#16() + 0x8f bytes
rpcrt4.dll!_Invoke#12() + 0x30 bytes
rpcrt4.dll!_NdrStubCall2#16() + 0x217 bytes
rpcrt4.dll!_NdrServerCall2#4() + 0x19 bytes
rpcrt4.dll!_DispatchToStubInCNoAvrf#12() + 0x17 bytes
rpcrt4.dll!RPC_INTERFACE::DispatchToStubWorker() + 0xae bytes
rpcrt4.dll!RPC_INTERFACE::DispatchToStub() + 0x4b bytes
rpcrt4.dll!LRPC_SCALL::DealWithRequestMessage() + 0x1d5 bytes
rpcrt4.dll!LRPC_ADDRESS::DealWithLRPCRequest() + 0x90 bytes
rpcrt4.dll!LRPC_ADDRESS::ReceiveLotsaCalls() + 0x20c bytes
rpcrt4.dll!RecvLotsaCallsWrapper() + 0xd bytes
rpcrt4.dll!BaseCachedThreadRoutine() + 0x92 bytes
rpcrt4.dll!ThreadStartRoutine() + 0x1b bytes
kernel32.dll!_BaseThreadStart#8() + 0x34 bytes
As per this book, the Telephony service will crash if TSPI_providerFreeDialogInstance is not implemented. I have implemented this function and DepWalker shows it as being properly exported. ApiSpy32 shows that its address is correctly returned via GetProcAddress when my TSP is loaded. Why is it still crashing?
The relevant code:
LONG TSPIAPI TSPI_lineMakeCall(DRV_REQUESTID dwRequestID, HDRVLINE hdLine, HTAPICALL htCall,
LPHDRVCALL lphdCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams)
{
OutputDebugString("TSPI_lineMakeCall\n");
PDRVLINE pLine = (PDRVLINE) hdLine;
*lphdCall = (HDRVCALL)hdLine;
typedef TUISPICREATEDIALOGINSTANCEPARAMS PARAMS;
pLine->htCall = htCall;
DWORD lLength = (lstrlenW(lpszDestAddress) + 1) * sizeof(WCHAR);
PARAMS* lParams = (PARAMS*)DrvAlloc(sizeof(PARAMS) + lLength);
RtlZeroMemory(lParams, sizeof(PARAMS) + lLength);
lParams->dwRequestID = dwRequestID;
lParams->hdDlgInst = (HDRVDIALOGINSTANCE)1000;
lParams->lpszUIDLLName = L"TapiAdapter.tsp";
lParams->lpParams = lParams + 1;
lParams->dwSize = lLength;
lstrcpyW((LPWSTR)(lParams + 1), lpszDestAddress);
(*pLine->pfnEventProc)(pLine->htLine, 0, LINE_CREATEDIALOGINSTANCE, (DWORD)lParams, 0, 0);
return dwRequestID;
}
LONG TSPIAPI TSPI_providerGenericDialogData(DWORD_PTR dwObjectID, DWORD dwObjectType, LPVOID lpParams, DWORD dwSize)
{
OutputDebugString("TSPI_providerGenericDialogData\n");
return 0;
}
LONG TSPIAPI TSPI_providerFreeDialogInstance(HDRVDIALOGINSTANCE hdDlgInst)
{
OutputDebugString("TSPI_providerFreeDialogInstance\n");
return 0;
}
LONG TSPIAPI TUISPI_providerGenericDialog(TUISPIDLLCALLBACK lpfnUIDLLCallback, HTAPIDIALOGINSTANCE htDlgInst, LPVOID lpParams, DWORD dwSize, HANDLE hEvent)
{
SetEvent(hEvent);
LPCWSTR lNumber = (LPCWSTR)lpParams;
MessageBoxW(0, lNumber, L"Dial Number", MB_OK);
return 0;
}
I don't know but the help for the TUISPICREATEDIALOGINSTANCEPARAMS Structure says that lpszUIDLLName should be a ...
pointer to a NULL-terminated string
specifying the fully qualified name of
the UI DLL to load in the application
context
... however L"TapiAdapter.tsp" doesn't look like a fully qualified name of the UI DLL ("fully-qualified" means that it includes the path name). Do you have a UI DLL to be loaded? Is it loaded? Does it display the dialog? Is it unloaded? Does TUISPI_providerGenericDialog exist in your TSP, or does it existin your UI DLL (they're supposed to be two different DLLs)?
I have found the solution: As per MSDN, the first parameter of the LINEEVENT call for this event only needs to be an HPROVIDER, not an HTAPILINE. Since the first parameter of LINEEVENT is of type HTAPILINE, the HPROVIDER will need to be cast.

Resources