updating svn mess

This commit is contained in:
Roel Verdult 2009-04-29 12:51:13 +00:00
parent bbae6dcee5
commit 7e221462a0
10 changed files with 962 additions and 863 deletions

187
acr122.c
View file

@ -1,187 +0,0 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <winscard.h>
#include <stdio.h>
#include <string.h>
#include "acr122.h"
#include "bitutils.h"
#define SCARD_OPERATION_SUCCESS 0x61
#define SCARD_OPERATION_ERROR 0x63
#define FIRMWARE_TEXT "ACR122U10" // ACR122U101(ACS), ACR122U102(Tikitag)
#define ACR122_WRAP_LEN 5
#define ACR122_COMMAND_LEN 266
#define ACR122_RESPONSE_LEN 268
#define MAX_READERS 16
static SCARDCONTEXT hCtx = null;
static byte abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
static byte abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 };
static byte uiRxCmdLen = sizeof(abtRxCmd);
static byte abtRxBuf[ACR122_RESPONSE_LEN];
static ulong ulRxBufLen;
static byte abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
static byte abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
dev_id acr122_connect(const ui32 uiDeviceIndex)
{
SCARDHANDLE hCard = null;
char* pacReaders[MAX_READERS];
char acList[256+64*MAX_READERS];
ulong ulListLen = sizeof(acList);
ulong ulActiveProtocol = 0;
ui32 uiPos;
ui32 uiReaderCount;
ui32 uiReader;
ui32 uiReaderIndex;
// Clear the reader list
memset(acList,0x00,ulListLen);
// Test if context succeeded
if (SCardEstablishContext(SCARD_SCOPE_USER,null,null,&hCtx) != SCARD_S_SUCCESS) return INVALID_DEVICE_ID;
// Retrieve the string array of all available pcsc readers
if (SCardListReaders(hCtx,null,acList,(void*)&ulListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_ID;
pacReaders[0] = acList;
uiReaderCount = 1;
for (uiPos=0; uiPos<ulListLen; uiPos++)
{
// Make sure don't break out of our reader array
if (uiReaderCount == MAX_READERS) break;
// Test if there is a next reader available
if (acList[uiPos] == 0x00)
{
// Test if we are at the end of the list
if (acList[uiPos+1] == 0x00)
{
break;
}
// Store the position of the next reader and search for more readers
pacReaders[uiReaderCount] = acList+uiPos+1;
uiReaderCount++;
}
}
// Initialize the reader index we are seaching for
uiReaderIndex = uiDeviceIndex;
// Iterate through all readers and try to find the ACR122 on requested index
for (uiReader=0; uiReader<uiReaderCount; uiReader++)
{
// Test if we were able to connect to the "emulator" card
if (SCardConnect(hCtx,pacReaders[uiReader],SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&hCard,(void*)&ulActiveProtocol) == SCARD_S_SUCCESS)
{
if (strstr(acr122_firmware((void*)hCard),FIRMWARE_TEXT) != null)
{
// We found a occurence, test if it has the right index
if (uiReaderIndex == 0)
{
// Done, we found the reader we are looking for
return (void*)hCard;
} else {
// Let's look for the next reader
uiReaderIndex--;
}
}
}
}
// Too bad, the reader could not be located;
return INVALID_DEVICE_ID;
}
void acr122_disconnect(const dev_id di)
{
SCardDisconnect((SCARDHANDLE)di,SCARD_LEAVE_CARD);
}
bool acr122_transceive(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
{
if (di == null) return false;
// Make sure the command does not overflow the send buffer
if (uiTxLen > ACR122_COMMAND_LEN) return false;
// Store the length of the command we are going to send
abtTxBuf[4] = uiTxLen;
#ifdef _LIBNFC_VERBOSE_
printf("Tx: ");
print_hex(pbtTx,uiTxLen);
#endif
// Prepare and transmit the send buffer
memcpy(abtTxBuf+5,pbtTx,uiTxLen);
ulRxBufLen = sizeof(abtRxBuf);
if (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtTxBuf,uiTxLen+5,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
// Make sure we received the byte-count we expected
if (ulRxBufLen != 2) return false;
// Check if the operation was successful, so an answer is available
if (*abtRxBuf == SCARD_OPERATION_ERROR) return false;
// Retrieve the response bytes
abtRxCmd[4] = abtRxBuf[1];
ulRxBufLen = sizeof(abtRxBuf);
if (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtRxCmd,uiRxCmdLen,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
// When the answer should be ignored, just return true
if (pbtRx == null || puiRxLen == null) return true;
// Make sure we have an emulated answer that fits the return buffer
if (ulRxBufLen < 4 || (ulRxBufLen-4) > *puiRxLen) return false;
// Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
*puiRxLen = ulRxBufLen-4;
memcpy(pbtRx,abtRxBuf+2,*puiRxLen);
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex(pbtRx,*puiRxLen);
#endif
// Transmission went successful
return true;
}
char* acr122_firmware(const dev_id di)
{
static char abtFw[11];
ulong ulFwLen = sizeof(abtFw);
memset(abtFw,0x00,ulFwLen);
SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtGetFw,sizeof(abtGetFw),null,(byte*)abtFw,(void*)&ulFwLen);
return abtFw;
}
bool acr122_led_red(const dev_id di, bool bOn)
{
byte abtBuf[2];
ulong ulBufLen = sizeof(abtBuf);
return (SCardTransmit((SCARDHANDLE)di,SCARD_PCI_T0,abtLed,sizeof(abtLed),null,(byte*)abtBuf,(void*)&ulBufLen) == SCARD_S_SUCCESS);
}

269
dev_acr122.c Normal file
View file

@ -0,0 +1,269 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "defines.h"
#include <winscard.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dev_acr122.h"
#include "bitutils.h"
// WINDOWS: #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
#define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
#define SCARD_OPERATION_SUCCESS 0x61
#define SCARD_OPERATION_ERROR 0x63
#ifndef SCARD_PROTOCOL_UNDEFINED
#define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
#endif
#define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
#define ACR122_WRAP_LEN 5
#define ACR122_COMMAND_LEN 266
#define ACR122_RESPONSE_LEN 268
#define MAX_READERS 16
typedef struct {
SCARDCONTEXT hCtx;
SCARDHANDLE hCard;
SCARD_IO_REQUEST ioCard;
} dev_spec_acr122;
static byte abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
static byte abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 };
static byte uiRxCmdLen = sizeof(abtRxCmd);
static byte abtRxBuf[ACR122_RESPONSE_LEN];
static ulong ulRxBufLen;
static byte abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
static byte abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
dev_info* dev_acr122_connect(const ui32 uiIndex)
{
char* pacReaders[MAX_READERS];
char acList[256+64*MAX_READERS];
ulong ulListLen = sizeof(acList);
ui32 uiPos;
ui32 uiReaderCount;
ui32 uiReader;
ui32 uiDevIndex;
dev_info* pdi;
dev_spec_acr122* pdsa;
dev_spec_acr122 dsa;
char* pcFirmware;
// Clear the reader list
memset(acList,0x00,ulListLen);
// Test if context succeeded
if (SCardEstablishContext(SCARD_SCOPE_USER,null,null,&(dsa.hCtx)) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
// Retrieve the string array of all available pcsc readers
if (SCardListReaders(dsa.hCtx,null,acList,(void*)&ulListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
#ifdef _LIBNFC_VERBOSE_
printf("Found the following PCSC device(s)\n");
printf("- %s\n",acList);
#endif
pacReaders[0] = acList;
uiReaderCount = 1;
for (uiPos=0; uiPos<ulListLen; uiPos++)
{
// Make sure don't break out of our reader array
if (uiReaderCount == MAX_READERS) break;
// Test if there is a next reader available
if (acList[uiPos] == 0x00)
{
// Test if we are at the end of the list
if (acList[uiPos+1] == 0x00)
{
break;
}
// Store the position of the next reader and search for more readers
pacReaders[uiReaderCount] = acList+uiPos+1;
uiReaderCount++;
// Debug info
#ifdef _LIBNFC_VERBOSE_
printf("- %s\n",acList+uiPos+1);
#endif
}
}
// Initialize the device index we are seaching for
uiDevIndex = uiIndex;
// Iterate through all readers and try to find the ACR122 on requested index
for (uiReader=0; uiReader<uiReaderCount; uiReader++)
{
// Test if we were able to connect to the "emulator" card
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_EXCLUSIVE,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// Connect to ACR122 firmware version >2.0
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_DIRECT,0,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// We can not connect to this device, we will just ignore it
continue;
}
}
// Configure I/O settings for card communication
dsa.ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST);
// Retrieve the current firmware version
pcFirmware = dev_acr122_firmware((dev_info*)&dsa);
if (strstr(pcFirmware,FIRMWARE_TEXT) != null)
{
// We found a occurence, test if it has the right index
if (uiDevIndex != 0)
{
// Let's look for the next reader
uiDevIndex--;
continue;
}
// Allocate memory and store the device specification
pdsa = malloc(sizeof(dev_spec_acr122));
*pdsa = dsa;
// Done, we found the reader we are looking for
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,pcFirmware);
pdi->ct = CT_PN532;
pdi->ds = (dev_spec)pdsa;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
// Too bad, the reader could not be located;
return INVALID_DEVICE_INFO;
}
void dev_acr122_disconnect(dev_info* pdi)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)pdi->ds;
SCardDisconnect(pdsa->hCard,SCARD_LEAVE_CARD);
SCardReleaseContext(pdsa->hCtx);
free(pdsa);
free(pdi);
}
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
// Make sure the command does not overflow the send buffer
if (uiTxLen > ACR122_COMMAND_LEN) return false;
// Store the length of the command we are going to send
abtTxBuf[4] = uiTxLen;
// Prepare and transmit the send buffer
memcpy(abtTxBuf+5,pbtTx,uiTxLen);
ulRxBufLen = sizeof(abtRxBuf);
#ifdef _LIBNFC_VERBOSE_
printf("Tx: ");
print_hex(abtTxBuf,uiTxLen+5);
#endif
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
if (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtTxBuf,uiTxLen+5,abtRxBuf,ulRxBufLen,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
} else {
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtTxBuf,uiTxLen+5,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
}
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_T0)
{
// Make sure we received the byte-count we expected
if (ulRxBufLen != 2) return false;
// Check if the operation was successful, so an answer is available
if (*abtRxBuf == SCARD_OPERATION_ERROR) return false;
// Retrieve the response bytes
abtRxCmd[4] = abtRxBuf[1];
ulRxBufLen = sizeof(abtRxBuf);
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtRxCmd,uiRxCmdLen,null,abtRxBuf,(void*)&ulRxBufLen) != SCARD_S_SUCCESS) return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex(abtRxBuf,ulRxBufLen);
#endif
// When the answer should be ignored, just return a succesful result
if (pbtRx == null || puiRxLen == null) return true;
// Make sure we have an emulated answer that fits the return buffer
if (ulRxBufLen < 4 || (ulRxBufLen-4) > *puiRxLen) return false;
// Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
*puiRxLen = ulRxBufLen-4;
memcpy(pbtRx,abtRxBuf+2,*puiRxLen);
// Transmission went successful
return true;
}
char* dev_acr122_firmware(const dev_spec ds)
{
ui32 uiResult;
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
static char abtFw[11];
ulong ulFwLen = sizeof(abtFw);
memset(abtFw,0x00,ulFwLen);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
uiResult = SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtGetFw,sizeof(abtGetFw),abtFw,ulFwLen,(void*)&ulFwLen);
} else {
uiResult = SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtGetFw,sizeof(abtGetFw),null,(byte*)abtFw,(void*)&ulFwLen);
}
#ifdef _LIBNFC_VERBOSE_
if (uiResult != SCARD_S_SUCCESS)
{
printf("No ACR122 firmware received, Error: %08x\n",uiResult);
}
#endif
return abtFw;
}
bool dev_acr122_led_red(const dev_spec ds, bool bOn)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
byte abtBuf[2];
ulong ulBufLen = sizeof(abtBuf);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
return (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtLed,sizeof(abtLed),abtBuf,ulBufLen,(void*)&ulBufLen) == SCARD_S_SUCCESS);
} else {
return (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtLed,sizeof(abtLed),null,(byte*)abtBuf,(void*)&ulBufLen) == SCARD_S_SUCCESS);
}
}

39
dev_acr122.h Normal file
View file

@ -0,0 +1,39 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBNFC_DEV_ACR122_H_
#define _LIBNFC_DEV_ACR122_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_acr122_connect(const ui32 uiIndex);
void dev_acr122_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_acr122_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
// Various additional features this device supports
char* dev_acr122_firmware(const dev_spec ds);
bool dev_acr122_led_red(const dev_spec ds, bool bOn);
#endif // _LIBNFC_DEV_ACR122_H_

247
dev_pn531.c Normal file
View file

@ -0,0 +1,247 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Thanks to d18c7db and Okko for example code
*/
#include "defines.h"
#include <usb.h>
#include <stdio.h>
#include <string.h>
#include "dev_pn531.h"
#include "bitutils.h"
#define BUFFER_LENGTH 256
#define USB_TIMEOUT 30000
static char buffer[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
typedef struct {
usb_dev_handle* pudh;
ui32 uiEndPointIn;
ui32 uiEndPointOut;
} dev_spec_pn531;
// Find transfer endpoints for bulk transfers
void get_end_points(struct usb_device *dev, dev_spec_pn531* pdsp)
{
ui32 uiIndex;
ui32 uiEndPoint;
struct usb_interface_descriptor* puid = dev->config->interface->altsetting;
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++)
{
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue;
// Copy the endpoint to a local var, makes it more readable code
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
// Test if we dealing with a bulk IN endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
{
#ifdef _LIBNFC_VERBOSE_
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointIn = uiEndPoint;
}
// Test if we dealing with a bulk OUT endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
{
#ifdef _LIBNFC_VERBOSE_
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointOut = uiEndPoint;
}
}
}
dev_info* dev_pn531_connect(const ui32 uiIndex)
{
int idvendor = 0x04CC;
int idproduct = 0x0531;
struct usb_bus *bus;
struct usb_device *dev;
dev_info* pdi = INVALID_DEVICE_INFO;
dev_spec_pn531* pdsp;
dev_spec_pn531 dsp;
ui32 uiDevIndex;
dsp.uiEndPointIn = 0;
dsp.uiEndPointOut = 0;
dsp.pudh = null;
usb_init();
if (usb_find_busses() < 0) return INVALID_DEVICE_INFO;
if (usb_find_devices() < 0) return INVALID_DEVICE_INFO;
// Initialize the device index we are seaching for
uiDevIndex = uiIndex;
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct)
{
// Make sure there are 2 endpoints available
if (dev->config->interface->altsetting->bNumEndpoints < 2) return pdi;
// Test if we are looking for this device according to the current index
if (uiDevIndex != 0)
{
// Nope, we maybe want the next one, let's try to find another
uiDevIndex--;
continue;
}
#ifdef _LIBNFC_VERBOSE_
printf("Found PN531 device\n");
#endif
// Open the PN531 USB device
dsp.pudh = usb_open(dev);
get_end_points(dev,&dsp);
if(usb_set_configuration(dsp.pudh,1) < 0)
{
#ifdef _LIBNFC_VERBOSE_
printf("Setting config failed\n");
#endif
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
if(usb_claim_interface(dsp.pudh,0) < 0)
{
#ifdef _LIBNFC_VERBOSE_
printf("Can't claim interface\n");
#endif
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
// Allocate memory for the device info and specification, fill it and return the info
pdsp = malloc(sizeof(dev_spec_pn531));
*pdsp = dsp;
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"PN531USB");
pdi->ct = CT_PN531;
pdi->ds = (dev_spec)pdsp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
}
return pdi;
}
void dev_pn531_disconnect(dev_info* pdi)
{
dev_spec_pn531* pdsp = (dev_spec_pn531*)pdi->ds;
usb_release_interface(pdsp->pudh,0);
usb_close(pdsp->pudh);
free(pdi->ds);
free(pdi);
}
bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen)
{
ui32 uiPos = 0;
int ret = 0;
char buf[BUFFER_LENGTH];
dev_spec_pn531* pdsp = (dev_spec_pn531*)ds;
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
buffer[3] = uiTxLen;
// Packet length checksum
buffer[4] = BUFFER_LENGTH - buffer[3];
// Copy the PN53X command into the packet buffer
memmove(buffer+5,pbtTx,uiTxLen);
// Calculate data payload checksum
buffer[uiTxLen+5] = 0;
for(uiPos=0; uiPos < uiTxLen; uiPos++)
{
buffer[uiTxLen+5] -= buffer[uiPos+5];
}
// End of stream marker
buffer[uiTxLen+6] = 0;
#ifdef _LIBNFC_VERBOSE_
printf("Tx: ");
print_hex((byte*)buffer,uiTxLen+7);
#endif
ret = usb_bulk_write(pdsp->pudh, pdsp->uiEndPointOut, buffer, uiTxLen+7, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf("usb_bulk_write failed with error %d\n", ret);
#endif
return false;
}
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf( "usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex((byte*)buf,ret);
#endif
if( ret == 6 )
{
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, buf, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef _LIBNFC_VERBOSE_
printf("usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef _LIBNFC_VERBOSE_
printf("Rx: ");
print_hex((byte*)buf,ret);
#endif
}
// When the answer should be ignored, just return a succesful result
if(pbtRx == null || puiRxLen == null) return true;
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
if(ret < 9) return false;
// Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
*puiRxLen = ret - 7 - 2;
memcpy( pbtRx, buf + 7, *puiRxLen);
return true;
}

View file

@ -1,36 +1,35 @@
/* /*
Public platform independent Near Field Communication (NFC) library Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _LIBNFC_ACR122_H_ #ifndef _LIBNFC_DEV_PN531_H_
#define _LIBNFC_ACR122_H_ #define _LIBNFC_DEV_PN531_H_
#include "defines.h" #include "defines.h"
#include "types.h" #include "types.h"
dev_id acr122_connect(const ui32 uiDeviceIndex); // Functions used by developer to handle connection to this device
void acr122_disconnect(const dev_id di); dev_info* dev_pn531_connect(const ui32 uiIndex);
bool acr122_transceive(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen); void dev_pn531_disconnect(dev_info* pdi);
bool acr122_transceive_(const dev_id di, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
char* acr122_firmware(const dev_id di); // Callback function used by libnfc to transmit commands to the PN53X chip
bool acr122_led_red(const dev_id di, bool bOn); bool dev_pn531_transceive(const dev_spec ds, const byte* pbtTx, const ui32 uiTxLen, byte* pbtRx, ui32* puiRxLen);
#endif // _LIBNFC_ACR122_H_ #endif // _LIBNFC_DEV_PN531_H_

225
mfread.c
View file

@ -1,225 +0,0 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libnfc.h"
#include "mifaretag.h"
static byte abtRecv[MAX_FRAME_LEN];
static ui32 uiRecvLen;
static dev_id di;
static MifareParam mp;
static MifareTag mtKeys;
static MifareTag mtDump;
bool is_trailer_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock+1)%4 == 0); else return ((uiBlock+1)%16 == 0);
}
ui32 get_trailer_block(ui32 uiSector)
{
// Test if we are in the small or big sectors
if (uiSector<32)
{
return (uiSector*4)+3;
} else {
return 128+((uiSector-32)*16)+15;
}
}
int main(int argc, const char* argv[])
{
bool b4K;
bool bKeyA;
byte* pbtUID;
bool bFailure;
i32 iBlock;
ui32 uiBlocks;
FILE* pfKeys;
FILE* pfDump;
MifareCmd mc;
if (argc < 4)
{
printf("mfread <a|b> <keys.mfd> <dump.mfd>\n");
printf("\n");
return 1;
}
bKeyA = (*(argv[1]) == 'a');
pfKeys = fopen(argv[2],"rb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[2]);
return 1;
}
fread(&mtKeys,1,sizeof(mtKeys),pfKeys);
fclose(pfKeys);
pfDump = fopen(argv[3],"wb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[3]);
return 1;
}
memset(&mtDump,0x00,sizeof(mtDump));
printf("Succesful opened MIFARE dump files\n");
// Try to open the NFC reader
di = acr122_connect(0);
if (di == INVALID_DEVICE_ID)
{
printf("Error connecting NFC reader\n");
return 1;
}
nfc_reader_init(di);
// Let the reader only try once to find a tag
nfc_configure_list_passive_infinite(di,false);
// Drop the field so the tag will be reset
nfc_configure_field(di,false);
// Configure the communication channel
nfc_configure_handle_crc(di,true);
nfc_configure_handle_parity(di,true);
printf("Connected to NFC reader\n");
// MIFARE Classic tag info = ( tag_count[1], tag_nr[1], ATQA[2], SAK[1], uid_len[1], UID[uid_len] )
uiRecvLen = MAX_FRAME_LEN;
if (!nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen))
{
printf("Error: no tag was found\n");
return 1;
}
// Test if we are dealing with a MIFARE compatible tag
if ((abtRecv[4] & 0x08) == 0)
{
printf("Error: tag is not a MIFARE Classic card\n");
return 1;
}
// Get the info from the key dump
b4K = (mtKeys.blContent[0].bm.abtATQA[0] == 0x02);
pbtUID = mtKeys.blContent[0].bm.abtUID;
// Compare if key dump UID is the same as the current tag UID
if (memcmp(abtRecv+6,pbtUID,4) != 0)
{
printf("Expected MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
}
// Get the info from the current tag
pbtUID = abtRecv+6;
b4K = (abtRecv[3] == 0x02);
printf("Found MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
uiBlocks = (b4K)?0xff:0x3f;
bFailure = false;
printf("Reading out %d blocks |",uiBlocks+1);
// Read the card from end to begin
for (iBlock=uiBlocks; iBlock>=0; iBlock--)
{
// Authenticate everytime we reach a trailer block
if (is_trailer_block(iBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen))
{
printf("!\nError: tag was removed\n");
return 1;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (iBlock != uiBlocks)
{
printf(".");
}
}
fflush(stdout);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,abtRecv+6,4);
// Determin if we should use the a or the b key
if (bKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.blContent[iBlock].bt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.blContent[iBlock].bt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(di,MC_AUTH_A,iBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",iBlock);
return 1;
}
// Try to read out the trailer
if (nfc_reader_mifare_cmd(di,MC_READ,iBlock,&mp))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mtDump.blContent[iBlock].bd.abtContent,mtKeys.blContent[iBlock].bt.abtKeyA,6);
memcpy(mtDump.blContent[iBlock].bt.abtAccessBits,mp.mpd.abtData+6,4);
memcpy(mtDump.blContent[iBlock].bd.abtContent+10,mtKeys.blContent[iBlock].bt.abtKeyB,6);
}
} else {
// Make sure a earlier readout did not fail
if (!bFailure)
{
// Try to read out the data block
if (nfc_reader_mifare_cmd(di,MC_READ,iBlock,&mp))
{
memcpy(mtDump.blContent[iBlock].bd.abtContent,mp.mpd.abtData,16);
} else {
bFailure = true;
}
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
printf("Writing dump to file: %s\n",argv[3]);
fflush(stdout);
fwrite(&mtDump,1,sizeof(mtDump),pfDump);
fclose(pfKeys);
printf("Done, all data is dumped!\n");
return 0;
}

374
mftool.c Normal file
View file

@ -0,0 +1,374 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "libnfc.h"
#include "mifaretag.h"
static dev_info* pdi;
static tag_info ti;
static mifare_param mp;
static mifare_tag mtKeys;
static mifare_tag mtDump;
static bool bUseKeyA;
static ui32 uiBlocks;
bool is_first_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock)%4 == 0); else return ((uiBlock)%16 == 0);
}
bool is_trailer_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock+1)%4 == 0); else return ((uiBlock+1)%16 == 0);
}
ui32 get_trailer_block(ui32 uiFirstBlock)
{
// Test if we are in the small or big sectors
if (uiFirstBlock<128) return uiFirstBlock+3; else return uiFirstBlock+15;
}
bool read_card()
{
i32 iBlock;
mifare_cmd mc;
bool bFailure = false;
printf("Reading out %d blocks |",uiBlocks+1);
// Read the card from end to begin
for (iBlock=uiBlocks; iBlock>=0; iBlock--)
{
// Authenticate everytime we reach a trailer block
if (is_trailer_block(iBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("!\nError: tag was removed\n");
return 1;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (iBlock != uiBlocks)
{
printf(".");
}
}
fflush(stdout);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
// Determin if we should use the a or the b key
if (bUseKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.amb[iBlock].mbt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(pdi,MC_AUTH_A,iBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",iBlock);
return false;
}
// Try to read out the trailer
if (nfc_reader_mifare_cmd(pdi,MC_READ,iBlock,&mp))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mtDump.amb[iBlock].mbt.abtKeyA,mtKeys.amb[iBlock].mbt.abtKeyA,6);
memcpy(mtDump.amb[iBlock].mbt.abtAccessBits,mp.mpd.abtData+6,4);
memcpy(mtDump.amb[iBlock].mbt.abtKeyB,mtKeys.amb[iBlock].mbt.abtKeyB,6);
}
} else {
// Make sure a earlier readout did not fail
if (!bFailure)
{
// Try to read out the data block
if (nfc_reader_mifare_cmd(pdi,MC_READ,iBlock,&mp))
{
memcpy(mtDump.amb[iBlock].mbd.abtData,mp.mpd.abtData,16);
} else {
bFailure = true;
}
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
return true;
}
bool write_card()
{
ui32 uiBlock;
ui32 uiTrailerBlock;
bool bFailure = false;
mifare_cmd mc;
printf("Writing %d blocks |",uiBlocks+1);
// Write the card from begin to end;
for (uiBlock=0; uiBlock<=uiBlocks; uiBlock++)
{
// Authenticate everytime we reach the first sector of a new block
if (is_first_block(uiBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("!\nError: tag was removed\n");
return false;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (uiBlock != 0)
{
printf(".");
}
}
fflush(stdout);
// Locate the trailer (with the keys) used for this sector
uiTrailerBlock = get_trailer_block(uiBlock);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,ti.tia.abtUid,4);
// Determin if we should use the a or the b key
if (bUseKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.amb[uiTrailerBlock].mbt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.amb[uiTrailerBlock].mbt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(pdi,mc,uiBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",uiBlock);
return false;
}
}
if (is_trailer_block(uiBlock))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mp.mpd.abtData,mtDump.amb[uiBlock].mbt.abtKeyA,6);
memcpy(mp.mpd.abtData+6,mtDump.amb[uiBlock].mbt.abtAccessBits,4);
memcpy(mp.mpd.abtData+10,mtDump.amb[uiBlock].mbt.abtKeyB,6);
// Try to write the trailer
nfc_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp);
} else {
// The first block 0x00 is read only, skip this
if (uiBlock == 0) continue;
// Make sure a earlier write did not fail
if (!bFailure)
{
// Try to write the data block
memcpy(mp.mpd.abtData,mtDump.amb[uiBlock].mbd.abtData,16);
if (!nfc_reader_mifare_cmd(pdi,MC_WRITE,uiBlock,&mp)) bFailure = true;
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
return true;
}
int main(int argc, const char* argv[])
{
bool b4K;
bool bReadAction;
byte* pbtUID;
FILE* pfKeys;
FILE* pfDump;
if (argc < 5)
{
printf("\n");
printf("mftool <r|w> <a|b> <keys.mfd> <dump.mfd>\n");
printf("\n");
printf("<r|w> - Perform (read from) or (write to) card\n");
printf("<a|b> - Use A or B keys to for action\n");
printf("<keys.mfd> - Mifare-dump that contain the keys\n");
printf("<dump.mfd> - Used to write (card to file) or (file to card)\n");
printf("\n");
return 1;
}
printf("\nChecking arguments and settings\n");
bReadAction = (tolower(*(argv[1])) == 'r');
bUseKeyA = (tolower(*(argv[2])) == 'a');
pfKeys = fopen(argv[3],"rb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[3]);
return 1;
}
if (fread(&mtKeys,1,sizeof(mtKeys),pfKeys) != sizeof(mtKeys))
{
printf("Could not read from keys file: %s\n",argv[3]);
fclose(pfKeys);
return 1;
}
fclose(pfKeys);
if (bReadAction)
{
memset(&mtDump,0x00,sizeof(mtDump));
} else {
pfDump = fopen(argv[4],"rb");
if (pfDump == null)
{
printf("Could not open dump file: %s\n",argv[4]);
return 1;
}
if (fread(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not read from dump file: %s\n",argv[4]);
fclose(pfDump);
return 1;
}
fclose(pfDump);
}
printf("Succesful opened MIFARE the required files\n");
// Try to open the NFC reader
pdi = nfc_connect();
if (pdi == INVALID_DEVICE_INFO)
{
printf("Error connecting NFC reader\n");
return 1;
}
nfc_reader_init(pdi);
// Drop the field for a while
nfc_configure(pdi,DCO_ACTIVATE_FIELD,false);
// Let the reader only try once to find a tag
nfc_configure(pdi,DCO_INFINITE_SELECT,false);
nfc_configure(pdi,DCO_HANDLE_CRC,true);
nfc_configure(pdi,DCO_HANDLE_PARITY,true);
// Enable field so more power consuming cards can power themselves up
nfc_configure(pdi,DCO_ACTIVATE_FIELD,true);
printf("Connected to NFC reader: %s\n",pdi->acName);
// Try to find a MIFARE Classic tag
if (!nfc_reader_select(pdi,IM_ISO14443A_106,null,null,&ti))
{
printf("Error: no tag was found\n");
nfc_disconnect(pdi);
return 1;
}
// Test if we are dealing with a MIFARE compatible tag
if ((ti.tia.btSak & 0x08) == 0)
{
printf("Error: tag is not a MIFARE Classic card\n");
nfc_disconnect(pdi);
return 1;
}
// Get the info from the key dump
b4K = (mtKeys.amb[0].mbm.abtATQA[1] == 0x02);
pbtUID = mtKeys.amb[0].mbm.abtUID;
// Compare if key dump UID is the same as the current tag UID
if (memcmp(ti.tia.abtUid,pbtUID,4) != 0)
{
printf("Expected MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
}
// Get the info from the current tag
pbtUID = ti.tia.abtUid;
b4K = (ti.tia.abtAtqa[1] == 0x02);
printf("Found MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
uiBlocks = (b4K)?0xff:0x3f;
if (bReadAction)
{
if (read_card())
{
printf("Writing data to file: %s\n",argv[4]);
fflush(stdout);
pfDump = fopen(argv[4],"wb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[4]);
return 1;
}
if (fwrite(&mtDump,1,sizeof(mtDump),pfDump) != sizeof(mtDump))
{
printf("Could not write to file: %s\n",argv[4]);
return 1;
}
fclose(pfDump);
printf("Done, all bytes dumped to file!\n");
}
} else {
if (write_card())
{
printf("Done, all data is written to the card!\n");
}
}
nfc_disconnect(pdi);
return 0;
}

232
mfwrite.c
View file

@ -1,232 +0,0 @@
/*
Public platform independent Near Field Communication (NFC) library
Copyright (C) 2009, Roel Verdult
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libnfc.h"
#include "mifaretag.h"
static byte abtRecv[MAX_FRAME_LEN];
static ui32 uiRecvLen;
static dev_id di;
static MifareParam mp;
static MifareTag mtKeys;
static MifareTag mtDump;
bool is_first_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock)%4 == 0); else return ((uiBlock)%16 == 0);
}
bool is_trailer_block(ui32 uiBlock)
{
// Test if we are in the small or big sectors
if (uiBlock < 128) return ((uiBlock+1)%4 == 0); else return ((uiBlock+1)%16 == 0);
}
ui32 get_trailer_block(ui32 uiFirstBlock)
{
// Test if we are in the small or big sectors
if (uiFirstBlock<128) return uiFirstBlock+3; else return uiFirstBlock+15;
}
int main(int argc, const char* argv[])
{
bool b4K;
bool bKeyA;
byte* pbtUID;
bool bFailure;
ui32 uiBlock;
ui32 uiBlocks;
ui32 uiTrailerBlock;
FILE* pfKeys;
FILE* pfDump;
MifareCmd mc;
if (argc < 4)
{
printf("mfwrite <a|b> <keys.mfd> <dump.mfd>\n");
printf("\n");
return 1;
}
bKeyA = (*(argv[1]) == 'a');
pfKeys = fopen(argv[2],"rb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[2]);
return 1;
}
fread(&mtKeys,1,sizeof(mtKeys),pfKeys);
fclose(pfKeys);
pfDump = fopen(argv[3],"rb");
if (pfKeys == null)
{
printf("Could not open file: %s\n",argv[3]);
return 1;
}
fread(&mtDump,1,sizeof(mtDump),pfDump);
fclose(pfDump);
printf("Succesful opened MIFARE dump files\n");
// Try to open the NFC reader
di = acr122_connect(0);
if (di == INVALID_DEVICE_ID)
{
printf("Error connecting NFC reader\n");
return 1;
}
nfc_reader_init(di);
// Let the reader only try once to find a tag
nfc_configure_list_passive_infinite(di,false);
// Drop the field so the tag will be reset
nfc_configure_field(di,false);
// Configure the communication channel
nfc_configure_handle_crc(di,true);
nfc_configure_handle_parity(di,true);
printf("Connected to NFC reader\n");
// MIFARE Classic tag info = ( tag_count[1], tag_nr[1], ATQA[2], SAK[1], uid_len[1], UID[uid_len] )
uiRecvLen = MAX_FRAME_LEN;
if (!nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen))
{
printf("Error: no tag was found\n");
return 1;
}
// Test if we are dealing with a MIFARE compatible tag
if ((abtRecv[4] & 0x08) == 0)
{
printf("Error: tag is not a MIFARE Classic card\n");
return 1;
}
// Get the info from the key dump
b4K = (mtKeys.blContent[0].bm.abtATQA[0] == 0x02);
pbtUID = mtKeys.blContent[0].bm.abtUID;
// Compare if key dump UID is the same as the current tag UID
if (memcmp(abtRecv+6,pbtUID,4) != 0)
{
printf("Expected MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
}
// Get the info from the current tag
pbtUID = abtRecv+6;
b4K = (abtRecv[3] == 0x02);
printf("Found MIFARE Classic %cK card with uid: %08x\n",b4K?'4':'1',swap_endian32(pbtUID));
uiBlocks = (b4K)?0xff:0x3f;
bFailure = false;
printf("Writing %d blocks |",uiBlocks+1);
// Write the card from begin to end;
for (uiBlock=0; uiBlock<=uiBlocks; uiBlock++)
{
// Authenticate everytime we reach the first sector of a new block
if (is_first_block(uiBlock))
{
// Show if the readout went well
if (bFailure)
{
printf("x");
// When a failure occured we need to redo the anti-collision
if (!nfc_reader_list_passive(di,MT_ISO14443A_106,null,null,abtRecv,&uiRecvLen))
{
printf("!\nError: tag was removed\n");
return 1;
}
bFailure = false;
} else {
// Skip this the first time, bFailure it means nothing (yet)
if (uiBlock != 0)
{
printf(".");
}
}
fflush(stdout);
// Locate the trailer (with the keys) used for this sector
uiTrailerBlock = get_trailer_block(uiBlock);
// Set the authentication information (uid)
memcpy(mp.mpa.abtUid,abtRecv+6,4);
// Determin if we should use the a or the b key
if (bKeyA)
{
mc = MC_AUTH_A;
memcpy(mp.mpa.abtKey,mtKeys.blContent[uiTrailerBlock].bt.abtKeyA,6);
} else {
mc = MC_AUTH_B;
memcpy(mp.mpa.abtKey,mtKeys.blContent[uiTrailerBlock].bt.abtKeyB,6);
}
// Try to authenticate for the current sector
if (!nfc_reader_mifare_cmd(di,mc,uiBlock,&mp))
{
printf("!\nError: authentication failed for block %02x\n",uiBlock);
return 1;
}
}
if (is_trailer_block(uiBlock))
{
// Copy the keys over from our key dump and store the retrieved access bits
memcpy(mp.mpd.abtData,mtDump.blContent[uiBlock].bt.abtKeyA,6);
memcpy(mp.mpd.abtData+6,mtDump.blContent[uiBlock].bt.abtAccessBits,4);
memcpy(mp.mpd.abtData+10,mtDump.blContent[uiBlock].bt.abtKeyB,6);
// Try to write the trailer
nfc_reader_mifare_cmd(di,MC_WRITE,uiBlock,&mp);
} else {
// The first block 0x00 is read only, skip this
if (uiBlock == 0) continue;
// Make sure a earlier write did not fail
if (!bFailure)
{
// Try to write the data block
memcpy(mp.mpd.abtData,mtDump.blContent[uiBlock].bd.abtContent,16);
if (!nfc_reader_mifare_cmd(di,MC_WRITE,uiBlock,&mp))
{
bFailure = true;
}
}
}
}
printf("%c|\n",(bFailure)?'x':'.');
fflush(stdout);
printf("Done, all data is written!\n");
return 0;
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="Windows-1252"?> <?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="8,00" Version="8.00"
Name="mfread" Name="mftool"
ProjectGUID="{BB0A837B-DAEF-4B3F-AF5B-9A757A97FFF3}" ProjectGUID="{BB0A837B-DAEF-4B3F-AF5B-9A757A97FFF3}"
RootNamespace="mfread" RootNamespace="mfread"
Keyword="Win32Proj" Keyword="Win32Proj"
@ -40,7 +40,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
@ -116,7 +116,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2" RuntimeLibrary="2"
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="3" WarningLevel="3"
@ -173,7 +173,7 @@
</References> </References>
<Files> <Files>
<File <File
RelativePath="..\mfread.c" RelativePath="..\mftool.c"
> >
</File> </File>
<File <File

View file

@ -1,185 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="mfwrite"
ProjectGUID="{77907F3D-BA6E-4A7F-AF9D-4F60C0A79952}"
RootNamespace="mfwrite"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(ConfigurationName)/libnfc.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="$(ConfigurationName)/libnfc.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\mfwrite.c"
>
</File>
<File
RelativePath="..\mifaretag.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>