Monday, March 31, 2014

Host Card Emulation Series: Card Agents and APDUs

In Android 4.4 to support HCE, HostApduService declares processCommandApdu() method that the developer needs to implement. The method processCommandApdu() is called when the service receives an Application Protocol Data Unit (APDU) sent by contactless/NFC reader. The developer needs to implement how to process APDUs specific to the card application(s) the service supports. The implementation can become complex if the service supports multiple card applications.

SimplyTapp SDK provides a robust architecture where each card application is implemented in a "card agent". Using SimplyTapp SDK, there is no need for the developer to implement a complex processCommandApdu() method for a service that supports multiple card applications. Instead the developer implements process() method in the card agent for each card application. A mobile application can support multiple card agents and card agents can be remotely deployed to the mobile application, similar to remotely deploying Java Card applet (aka cardlet) to the Secure Element. Essentially SimplyTapp SDK provides an architecture that is familiar to Java Card developers.

I will describe how the card agent processes different APDU cases as defined in ISO/IEC 7816-4 specification.
ISO 7816-4 Case 1 No Lc
No Le
Example: 80100000
ISO 7816-4 Case 2 No Lc
1-byte Le (1 to 256, Le=0x00 represents 256)
Example: 8012000000
ISO 7816-4 Case 3 1-byte Lc (1 to 255)
No Le
Example: 80140000081112131415161718
ISO 7816-4 Case 4 1-byte Lc (1 to 255)
1-byte Le (1 to 256, Le=0x00 represents 256)
Example: 8016000008212223242526272800

Here is sample code for card agent implementation that demonstrates how to process the example APDUs. The class extends com.simplytapp.virtualcard.Agent.
 import javacard.framework.APDU;  
 import javacard.framework.ISO7816;  
 import javacard.framework.ISOException;  
   
 import com.simplytapp.virtualcard.Agent;  
   
 public class CardAgent extends Agent {  
   
   public void process(APDU apdu) throws ISOException {  
     byte[] apduBuffer = apdu.getBuffer();  
     byte claByte = apduBuffer[ISO7816.OFFSET_CLA];  
     byte insByte = apduBuffer[ISO7816.OFFSET_INS];  
   
     if (claByte == (byte) 0x80) {  
       if (insByte == (byte) 0x10) {  
         // Process case 1 command APDU.  
         processCase1Apdu();  
   
         // Return SW=0x9000.  
       }  
       else if (insByte == (byte) 0x12) {  
         // Process case 2 command APDU.  
   
         // Copy response data to APDU buffer.  
         System.arraycopy(responseData, 0,   
             apduBuffer, 0, responseData.length);  
   
         short le = apdu.setOutgoing();  
         if (responseData.length > le) {  
           le = (short) responseData.length;  
         }  
         apdu.setOutgoingLength(le);  
         apdu.sendBytes((short) 0, le);  
         // Return response data with SW=0x9000.  
       }  
       else if (insByte == (byte) 0x14) {  
         // Process case 3 command APDU.  
         short lc = apdu.setIncomingAndReceive();  
   
         // Save command data from APDU buffer.  
         System.arraycopy(apduBuffer, ISO7816.OFFSET_CDATA,   
             commandData, 0, lc);  
   
         // Return SW=0x9000.  
       }  
       else if (insByte == (byte) 0x16) {  
         // Process case 4 command APDU.  
         short lc = apdu.setIncomingAndReceive();  
   
         // Save command data from APDU buffer.  
         System.arraycopy(apduBuffer, ISO7816.OFFSET_CDATA,   
             commandData, 0, lc);  
   
         // Copy response data to APDU buffer.  
         System.arraycopy(responseData, 0,   
             apduBuffer, 0, responseData.length);  
   
         short le = apdu.setOutgoing();  
         if (responseData.length > le) {  
           le = (short) responseData.length;  
         }  
         apdu.setOutgoingLength(le);  
         apdu.sendBytes((short) 0, le);  
         // Return response data with SW=0x9000.  
       }  
     }  
   }  
   
 }  

The card agent can also process extended length APDUs as defined in ISO/IEC 7816-4 specification. The maximum supported length using extended length is 32767 to be consistent with Java Card API.
ISO 7816-4 Case 1 Not Applicable
ISO 7816-4 Case 2 No Lc
3-byte Le (1 to 32767, Le=0x000000 represents 32767)
Example: 80120000000000
ISO 7816-4 Case 3 3-byte Lc (1 to 32767)
No Le
Example: 801400000000081112131415161718
ISO 7816-4 Case 4 3-byte Lc (1 to 32767)
2-byte Le (1 to 32767, Le=0x0000 represents 32767)
Example: 8016000000000821222324252627280000

Here is sample code for card agent implementation that demonstrates how to process the example extended length APDUs. The class extends com.simplytapp.virtualcard.Agent and implements javacardx.apdu.ExtendedLength.
 import javacard.framework.APDU;  
 import javacard.framework.ISO7816;  
 import javacard.framework.ISOException;  
 import javacardx.apdu.ExtendedLength;  
   
 import com.simplytapp.virtualcard.Agent;  
   
 public class CardAgent extends Agent implements ExtendedLength {  
   
   public void process(APDU apdu) throws ISOException {  
     byte[] apduBuffer = apdu.getBuffer();  
     byte claByte = apduBuffer[ISO7816.OFFSET_CLA];  
     byte insByte = apduBuffer[ISO7816.OFFSET_INS];  
   
     if (claByte == (byte) 0x80) {  
       if (insByte == (byte) 0x12) {  
         // Process case 2 command APDU.  
   
         // Copy response data to APDU buffer.  
         System.arraycopy(responseData, 0,   
             apduBuffer, 0, responseData.length);  
   
         short le = apdu.setOutgoing();  
         if (responseData.length > le) {  
           le = (short) responseData.length;  
         }  
         apdu.setOutgoingLength(le);  
         apdu.sendBytes((short) 0, le);  
         // Return response data with SW=0x9000.  
       }  
       else if (insByte == (byte) 0x14) {  
         // Process case 3 command APDU.  
         short receivedLen = apdu.setIncomingAndReceive();  
   
         // Save command data from APDU buffer.  
         System.arraycopy(apduBuffer, apdu.getOffsetCdata(),   
             commandData, 0, receivedLen);  
   
         short lc = apdu.getIncomingLength();  
         // Check if additional command data not yet received.  
         if (receivedLen != lc) {  
           short commandDataOffset = receivedLen;  
   
           // Receive more command data until no more available.  
           receivedLen = apdu.receiveBytes((short) 0);  
           while (receivedLen != 0) {  
             // Save additional command data from APDU buffer.  
             System.arraycopy(apduBuffer, 0,   
                 commandData, commandDataOffset, receivedLen);  
             commandDataOffset += receivedLen;  
             receivedLen = apdu.receiveBytes((short) 0);  
           }  
         }  
   
         // Return SW=0x9000.  
       }  
       else if (insByte == (byte) 0x16) {  
         // Process case 4 command APDU.  
         short receivedLen = apdu.setIncomingAndReceive();  
   
         // Save command data from APDU buffer.  
         System.arraycopy(apduBuffer, apdu.getOffsetCdata(),   
             commandData, 0, receivedLen);  
   
         short lc = apdu.getIncomingLength();  
         // Check if additional command data not yet received.  
         if (receivedLen != lc) {  
           short commandDataOffset = receivedLen;  
   
           // Receive more command data until no more available.  
           receivedLen = apdu.receiveBytes((short) 0);  
           while (receivedLen != 0) {  
             // Save additional command data from APDU buffer.  
             System.arraycopy(apduBuffer, 0,   
                 commandData, commandDataOffset, receivedLen);  
             commandDataOffset += receivedLen;  
             receivedLen = apdu.receiveBytes((short) 0);  
           }  
         }  
   
         // Copy response data to APDU buffer.  
         System.arraycopy(responseData, 0,   
             apduBuffer, 0, responseData.length);  
   
         short le = apdu.setOutgoing();  
         if (responseData.length > le) {  
           le = (short) responseData.length;  
         }  
         apdu.setOutgoingLength(le);  
         apdu.sendBytes((short) 0, le);  
         // Return response data with SW=0x9000.  
       }  
     }  
   }  
   
 }  

Friday, March 14, 2014

Host Card Emulation Series: Contactless Debit, A Merchants Advantage

Contactless Debit, A Merchants Advantage



Host Card Emulation (HCE) brings new opportunity for merchants. In a recent trip to Whole Foods, who installed contactless terminals some time ago, I decided to try my debit card using the Tapp mobile test wallet.  After grabbing some lunch I headed to the register, and proceeded to checkout.  I tapped my phone to the contactless terminal and VOILA! The terminal asked me for my pin, I entered it, grabbed my lunch and off I went.

So why is this important?  The answer requires a look back at where the dynamics of the payments industry was just a few years ago.

The “Way back Machine”

In the semi-beginning, circa 2011, NFC mobile wallets meant Google Wallet, ISIS and the MNOs controlled SE model.  The idea was pretty straight forward one device, one SE, maybe one credit card, and POW!!! BAMM!! Goldmine! Right...Wrong! What happened? A back lash by merchants, banks and just about everyone but the MNOs.  In front of the new push for mobile payments stood a number of hurdles that needed to be cleared.  One of the most sizable hurdles being the merchants feeling that Contactless = Higher Transaction Costs.

Merchants viewed NFC as a more expensive transaction form and in the SE model that was largely true. For example, the average cost of a debit transaction tops out at around $0.30 in the US compared to the potentially much higher cost credit transaction, roughly $0.10 + 1.7% or more.  So what happened? Merchants, led by Walmart, huddled together in an attempt to break down mobile payment progress and keep transaction costs down. They called it MCX. Their message could generally be summed up with the following statement “Hell No, We Won’t Go!”  This stance led to a lot of head scratching as how mobile payment adoption would or could progress. But quietly the ground began to soften and HCE took root. 

“Bing, please enter PIN”

Coming back to my experience at Whole Foods and why it is important. 

The goal of any merchant is to sell goods or services to customers in exchange for assets, typically money, that has a greater value to the merchant than the goods and services being sold.  Pretty straight forward, but how that exchange actually takes place is where we will have our conversation. 
When it comes to merchants convincing consumers to part with their money they want to make it as easy as possible. Today there are, generally speaking, a handful of payments options as presented below:

  • Cash – used often and easily accepted;
  • Check – rarely used anymore and rather hard and slow to use;
  • Credit – used often and extremely easy for both cashier and customer;
  • Debit – used most often and equal to credit for ease of use;
  • GiftCard/Stored Value – used on a regular basis and considered as easy to use as other plastic forms. 

Each payment option has advantages and disadvantages regarding availability, ease of use and cost of managing and accepting.   More importantly all these payment form factors excluding only cash and check can be all accepted over the contactless channel. This means that merchants now have increased opportunity to influence customers when it comes to selecting payment forms like debit and gift/stored value cards over their more expensive siblings.

It means the power of payment is now in the hands of the merchant.  To illustrate a practical example of this is the case study of Spec’s, a merchant that communicates to their customers the importance of selecting the right payment form.

Debit Strategy: Spec’s


Spec’s is a merchant in Texas that manages their transaction cost extremely well.  Every check out register displays the options and cost of the options and every cashier asks the customer if they would like a 5% discount for using Cash or Debit.  Pretty easy to make that decision for me.  I simply present my debit card and save the money up front.  It is not just Spec’s that takes this simplified approach but other merchants as well. 

Conclusion

HCE offers merchants and banks alike new opportunities to influence consumers’ payment behavior like never before.  As Spec’s demonstrates, customer are willing to pay cash or use debit when offered discounts at the register. Speaking from experience I know this is true. However, merchants should understand that offering consumers incentive to select the less expensive debit or gift/stored value card is a window that will not stat open forever as the pace of adoption continues to accelerate. There are already merchants implementing effective transactions cost reducing strategies.  Moving these same strategies into the mobile space only enhance the merchants’ position in a consumers mind at the time of check out.