element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Internet of Things
  • Technologies
  • More
Internet of Things
Blog Digital Logic µFR NFC Card Reader - part 3: C++ Class to handle ISO14443 / APDU cards
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Internet of Things to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 16 Dec 2020 12:15 PM Date Created
  • Views 1238 views
  • Likes 2 likes
  • Comments 1 comment
  • infineon
  • security2go
  • smartcard
  • iso14443
  • nfc
Related
Recommended

Digital Logic µFR NFC Card Reader - part 3: C++ Class to handle ISO14443 / APDU cards

Jan Cumps
Jan Cumps
16 Dec 2020

In this article I make a c++ application for the D-Logic card reader and a set of smart cards.

This time I make a class that can deal with ISO14443 protocol.

image

 

Specialised Interface for ISO14443 / APDU Cards

 

I have a set of ISO14443 cards (from a roadtest) that support the ISO14443_4 protocol.

They support a smart card protocol called APDU. I've reviewed that in Blockchain - Talk Directly to the Infineon 2Go Smart Cards API.

In this post, I'm extending my little c++ framework to deal with cards that support the protocol.

 

These cards are a "normal" smart card  by default. The difference is that they support the APDU mode, by asking them to switch.

Then, they support an extra set of commands.

 

I modeled that in the framework by:

  • Making ISO14443 card class a normal card by default. The class inherits from Card.
  • I made an interface that defines the ISO14443 behaviour.
  • The ISO14443 card class implements that interface.

You can use the card in code that expects a normal card. It will work.

You can pass it to code that's expecting objects that comply to the ISO14443 interface. That will work too.

 

image

 

This is the CardISO14443 declaration code:

 

class CardISO14443: public Card, public IfaceISO14443 {
public:
  CardISO14443(const Reader *reader, const uint8_t sac,
      const std::array<uint8_t, 10> id, const uint8_t size);
  virtual ~CardISO14443();
  virtual void setISO14443_4() override;
};

 

The CardISO14443 inherits from Card. It automatically gets all the behaviour.

It also inherits from the interface IfaceISO14443. There is no behaviour to inherit here because the interface only defines an API. It does not implement anything.

Multiple inheritance is often a discussion point. You can search the internet and spend days reading critique.

The use here, as a way to define interfaces and implement them, isn't one of the controversial uses though.

Although there are several other ways to achieve what I'm doing, this is a common approach.

I'm at the start of the framework design, so I haven't really decided how the final OO design will be.

But this approach keeps options open. I like building the framework part by part, and refine, extend, simplify, style it along the way. Based on a real application need.

 

When the card object is created, it behaves as a Card:

 

    Card *crd = reader->getCard();

    IfaceISO14443 *isocrd = dynamic_cast<IfaceISO14443*> (crd);

    if (isocrd != NULL) {
      std::cout << "this is an ISO14443 capable card" << std::endl;
      isocrd->setISO14443_4();
    } else {
      std::cout << "card id: " << *crd << std::endl;
    }
    reader->releaseCard(crd);

 

I test its ISO144443 behaviour by casting it to a IfaceISO14443.

The function used to do that is called dynamic_cast.

 

IfaceISO14443 *isocrd = dynamic_cast<IfaceISO14443*> (crd);

 

This is a safe way to check if an object is of a certain class. If it isn't, the function returns a null pointer.

If it is of the requested type, it returns a valid pointer that is of that type, and can be type-safe used further down the road.

Here, after checking it's a ISO144443 type, I use it as such and flip operation to the ISO14443_4 protocol:

 

    if (isocrd != NULL) {
      std::cout << "this is an ISO14443 capable card" << std::endl;
      isocrd->setISO14443_4();
    } 
    // ...

 

Code

 

Card object creation:

 

I change the way the reader object creates a card. If it's a normal one, it creates a Card.

If it's one of the fancy ones, it creates a specialised object.

Note that for our code, it still looks like a normal card and can be used as such.

 

Card* UfrReader::getCard() {
  uint8_t lpucSak = 0;
  uint8_t aucUid[10];
  uint8_t lpucUidSize = 0;
  std::array<uint8_t, 10> id;

  UfrFactory::Status status = UfrFactory::retvalConvert(
      GetCardIdEx(&lpucSak, aucUid, &lpucUidSize));
  if (status != UfrFactory::UFR_OK) {
    throw ReaderException(status);
  }

  // if DL_MIFARE_MINI, the ID is to be ignored.
  // Create an ISO14443_4 card
  Card *card = NULL;

  if (lpucSak == DL_MIFARE_MINI) {
    card = new CardISO14443(this, lpucSak, id, lpucUidSize);
  } else {
    std::copy(std::begin(aucUid), std::end(aucUid), id.begin());
    card = new Card(this, lpucSak, id, lpucUidSize);
  }

  return card;
}

 

I first get initial card info from D-Logic's library.

If it is a special card (I use the card type for that. My code isn't complete - there are more types that implement APDU) I create a CardISO14443.

Else I use the original code to generate a normal Card.

The method return type is Card *.  Whatever the object that's created.

And that's what we designed. They are in both cases of type Card.

image

Interface

 

I implemented is as a c++ abstract class. It has specifications but (deliberate) no implementation.

 

class IfaceISO14443 {
public:
  virtual ~IfaceISO14443() {
  }
  virtual void setISO14443_4() = 0;
};

 

(again: this is incomplete. There are a number of functions related to APDU. I implemented one as a proof of concept)

This is what makes the class abstract:

 

virtual void setISO14443_4() = 0;

 

The method is virtual and is set to "0": not implemented here.

It's the responsibility of the classes that implement the interface to provide the function.

image

In our case, that's the CardISO14443 class.

 

The CardISO14443 class implements the interface:

 

class CardISO14443: public Card, public IfaceISO14443 {
public:
  CardISO14443(const Reader *reader, const uint8_t sac,
      const std::array<uint8_t, 10> id, const uint8_t size);
  virtual ~CardISO14443();

  virtual void setISO14443_4() override;
};

 

Here's where we indicate we implement the interface (also shown at the start of the article):

 

class CardISO14443: public Card, public IfaceISO14443 {


We have to implement the pure virtual function. It's flagged here:

virtual void setISO14443_4() override;

 

The implementation itself:

 

void CardISO14443::setISO14443_4() {
  UfrFactory::Status status = UfrFactory::retvalConvert(SetISO14443_4_Mode());
  if (status != UfrFactory::UFR_OK) {
    throw CardException(status);  }
}

 

It sets operation to ISO14443_4 mode.

Any code that knows how to deal with IfaceISO14443 can call this method (also shown earlier):

 

    IfaceISO14443 *isocrd = dynamic_cast<IfaceISO14443*> (crd);
    if (isocrd != NULL) {
     // ....
      isocrd->setISO14443_4();
    }

 

That's it for now. I'm now at a point where I can set up a meaningful APDU conversation.

The current project state is attached to this post.

 

Related Blog
Blockchain - Talk Directly to the Infineon 2Go Smart Cards API
NFC Card Reader Protocol of Digital Logic µFR - part 0: intent
µFR NFC Card Reader - part 1: first C program for Linux (RPi, BB, ...)
µFR NFC Card Reader - part 2: first C++ program
µFR NFC Card Reader - part 3: C++ Class to handle ISO14443 / APDU cards
µFR NFC Card Reader - part 4: first meaningful ISO14443 / APDU conversation
µFR NFC Card Reader - part 5: refactor, look back at initial design
Attachments:
digitallogic_rfc_cpp_20201216.zip
  • Sign in to reply

Top Comments

  • Jan Cumps
    Jan Cumps over 4 years ago +1
    The first meaningful conversations with an Infineon Security2Go card: This is where I wanted to get with the exercise: access to the card's application (yes: it runs software). In this exercise, I start…
  • Jan Cumps
    Jan Cumps over 4 years ago

    The first meaningful conversations with an Infineon Security2Go card:

    image

     

    This is where I wanted to get with the exercise: access to the card's application (yes: it runs software).

    In this exercise, I start an application session, and get the card's ID back.

    I've used the Android app and example software of my card reader before, to see such a conversation.

    This is the first back-and forth from my OO design here.

     

    In short:

    • recognise that the card supports the ISO14443_4 protocol and set it to that mode
    • ask to open an application session
    • the card responds with its ID (this is the state when I took the screen capture above)
    • close the session
    • card is back into "normal" smart card mode.
    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube