Sending APDUs

This commit is contained in:
Ondrej Mikle 2014-07-21 17:29:45 +02:00
parent 703c214421
commit 6ae565373a
3 changed files with 127 additions and 1 deletions

View file

@ -9,9 +9,23 @@
using namespace std; using namespace std;
ResponseAPDU::ResponseAPDU(const string &data)
{
size_t len = data.size();
_valid = len >= 2;
if (!_valid) {
return;
}
_sw = (uint8_t(data[len-2]) << 8) | uint8_t(data[len-1]);
_data = data.substr(0, len-2);
}
NFCDevice::NFCDevice() throw(NFCError): NFCDevice::NFCDevice() throw(NFCError):
pollNr(20), pollNr(20),
pollPeriod(2), pollPeriod(2),
apduTimeout(500),
_nfcContext(NULL), _nfcContext(NULL),
_nfcDevice(NULL), _nfcDevice(NULL),
_opened(false), _opened(false),
@ -105,6 +119,36 @@ std::string NFCDevice::scanUID() throw(NFCError)
return uid; return uid;
} }
void NFCDevice::selectPassiveTarget() throw(NFCError)
{
nfc_target nt;
while (nfc_initiator_select_passive_target(_nfcDevice, _modulations[0], NULL, 0, &nt) <= 0);
}
ResponseAPDU NFCDevice::sendAPDU(const string &apdu) throw(NFCError)
{
int res;
uint8_t rapdu[512];
if ((res = nfc_initiator_transceive_bytes(_nfcDevice, (uint8_t*)apdu.data(), apdu.size(),
rapdu, 512, apduTimeout)) < 0) {
if (res == NFC_EOVFLOW) {
throw NFCError("Response APDU too long");
}
throw NFCError("Failed to transceive APDU");
} else {
string rapduData((char *)rapdu, res);
ResponseAPDU responseApdu(rapduData);
if (!responseApdu.valid()) {
throw NFCError("Invalid response APDU was received");
}
return responseApdu;
}
}
const nfc_modulation NFCDevice::_modulations[5] = { const nfc_modulation NFCDevice::_modulations[5] = {
{ /*.nmt = */ NMT_ISO14443A, /* .nbr = */ NBR_106 } { /*.nmt = */ NMT_ISO14443A, /* .nbr = */ NBR_106 }
//{ /*.nmt = */ NMT_ISO14443B, /* .nbr = */ NBR_106 }, //{ /*.nmt = */ NMT_ISO14443B, /* .nbr = */ NBR_106 },

View file

@ -29,6 +29,45 @@ protected:
std::string _msg; std::string _msg;
}; };
/**
* Represents response APDU for ISO14443-4.
*/
class ResponseAPDU
{
public:
/** Parse response APDU from raw data */
ResponseAPDU(const std::string& data);
~ResponseAPDU() {}
/** Return whole status word */
uint16_t sw() const {return _sw;}
/** Return first byte of status word */
uint8_t sw1() const {return _sw >> 8;}
/** Return second byte of status word */
uint8_t sw2() const {return _sw & 0xFF;}
/** Return whether this is properly formed response */
bool valid() const {return _valid;}
/** Returns APDU data */
const std::string& data() const {return _data;}
private:
/** Data from response, without SW1 and SW2 */
std::string _data;
/** SW1 and SW2 */
uint16_t _sw;
/** Whether response APDU has had enough data to be valid */
bool _valid;
};
/** /**
* Represents one PN532 reader device. Config is taken from default * Represents one PN532 reader device. Config is taken from default
* libnfc-specified location. That usually means first device found is used. * libnfc-specified location. That usually means first device found is used.
@ -68,6 +107,20 @@ public:
*/ */
std::string scanUID() throw(NFCError); std::string scanUID() throw(NFCError);
/**
* Wait for one passive or emulated target and select it by reader.
*/
void selectPassiveTarget() throw(NFCError);
/**
* Send APDU to passive or emulated target. The target must be already
* selected by selectPassiveTarget() or scanUID().
*
* @param apdu command APDU to send
* @param returns response APDU received from target
*/
ResponseAPDU sendAPDU(const std::string& apdu) throw(NFCError);
/** Open device explicitly. May be useful after explicit close */ /** Open device explicitly. May be useful after explicit close */
void open() throw(NFCError); void open() throw(NFCError);
@ -95,6 +148,11 @@ public:
*/ */
uint8_t pollPeriod; uint8_t pollPeriod;
/**
* Timeout for waiting response to sent APDU. Value -1 means wait forever.
*/
int apduTimeout;
protected: protected:
/** Modulations that specify cards accepted by reader */ /** Modulations that specify cards accepted by reader */

View file

@ -2,9 +2,33 @@
from brmdoor_nfc import NFCDevice, NFCError from brmdoor_nfc import NFCDevice, NFCError
from binascii import hexlify from binascii import hexlify
def formatAPDU(apdu):
return " ".join(["%02X" % ord(b) for b in apdu])
# Reading of file E104, where usually NDEF message is
hex_apdus = [
"00 A4 04 00 07 D2760000850101",
"00 a4 00 0c 02 E104",
"00 b0 00 00 30",
]
apdus = [hex_apdu.replace(" ","").decode("hex") for hex_apdu in hex_apdus]
try: try:
nfc = NFCDevice() nfc = NFCDevice()
print hexlify(nfc.scanUID()) uid = nfc.scanUID()
print "UID", hexlify(uid)
print "Now trying to send ISO14443-4 APDUs"
try:
#nfc.selectPassiveTarget()
for apdu in apdus:
print "Command APDU:", formatAPDU(apdu)
rapdu = nfc.sendAPDU(apdu)
print "Response APDU valid: %s, SW %04x, data %s" % (rapdu.valid(), rapdu.sw(), hexlify(rapdu.data()))
except NFCError, e:
print "Failed to transmit APDU:", e.what()
print "Device is opened:", nfc.opened() print "Device is opened:", nfc.opened()
print "Closing device" print "Closing device"
nfc.close() nfc.close()