Tuesday, January 7, 2014

Host Card Emulation Series: SwipeYours - Tap Using A Card From Your Wallet

While various Android HCE (Host Card Emulation) examples have been popping up, until now there has been no simple examples that could be easily tested with live payment terminals. SwipeYours fills this space.

SwipeYours is a small, self contained app from which your card data never leaves the phone except to make NFC payments.  It uses the Visa-MSD (Magnetic Stripe Data) protocol to make tap payments. While Visa-MSD is now deprecated, it is supported by most NFC payment terminals in North America and this is unlikely to change in the near future. In Austin, TX we’ve successfully used SwipeYours at all of the following:

  • CVS drugstore
  • McDonald’s
  • Jack in the Box
  • Taco Bell
  • Jamba Juice
  • Valero Gas Stations


Links:


What you need to use SwipeYours:
  • A magnetic stripe reader to pull your card data. These can be purchased cheaply on both Amazon and Ebay in the US.
  • An NFC phone running Android 4.4+ (KitKat or above).
  • A non-chipped Visa credit or debit card. If the card already has a smart chip for native tap payments, the authorization processor is most likely expecting a different variation of Visa MSD than what we can provide. 
  • An issuing bank (or its outsourced processor) that does not check the delivery method: swipe, dip or tap.The processor has access to the delivery method of the card data and can reject a tap transaction if it wants to. All tested prepaid Visa cards have not had this issue and most major banks like Chase work fine. Capital One cards and the processor for some small credit unions, unfortunately, do have this issue.

Small Print Disclaimer:

SimplyTapp does not encourage the storage of payment credentials on your phone and provides secure cloud based solutions.  I have provided the source code and Google play download via my personal Github and Google accounts respectively.  Adding your own magnetic stripe data to SwipeYours may work, but it is not a supported payment method by Visa or your issuing bank.  


Visa-MSD Payment example:

Applications implementing HCE send and receive data with a POS (Point Of Sale) terminal using a byte array abstraction called an APDU (Application Protocol Data Unit).

The MainActivity of SwipeYours logs these APDU exchanges to the screen so developers can better understand how the process works.  Below I’ll show the data from a typical Visa-MSD transaction performed by SwipeYours.  If you want to better understand the values in the hex strings below, the source code to the SwipeYours PaymentService has lots of detailed comments.

POS SwipeYours

PaymentService Received PPSE select: 00A404000E325041592E5359532E444446303100

Here the POS sent our app a PPSE (Proximity Payment Service Environment) select.  This is the first APDU sent in any payment transaction.  It asks the payment device to send a list of supported payment types.

The AID (Application IDentifier) in the request is highlighted in red. It's the ASCII string 2PAY.SYS.DDF01 represented in hexadecimal.  If you are not using HCE (Host Card Emulation), these select statements would be delivered to a JavaCard applet registered to that AID.  JavaCard is a subset of Java designed for low power chips.

With HCE, there is no requirement to use JavaCard applets.  The PaymentService entry in our Android manifest specifies a list of AID values that should be directed to our service.


POS SwipeYours

Response: 6F23840E325041592E5359532E4444463031A511BF0C0E610C4F07A00000000310108701019000

Our PPSE response contains a single AID value letting the POS know that we only support Visa credit and debit transactions.  


POS SwipeYours

PaymentService Received Visa-MSD select: 00A4040007A000000003101000

Now the POS selects the only payment AID that we offered above.


POS SwipeYours

Response: 6F1E8407A0000000031010A513500B56495341204352454449549F38039F66029000

SwipeYours sends Visa-MSD select response. For trivia sake, the second value in red above is the ASCII string VISA CREDIT represented in hexadecimal.

POS SwipeYours

PaymentService Received GPO: 80A80000048302800000

POS sends the Get Processing Options (GPO) command.


POS SwipeYours

Response: 80060080080101009000

Payment devices supporting Visa transactions can support different payment protocols (Visa uses the term "path" instead of protocol).  Our response lets the POS terminal know that we only support Visa-MSD.   Our GPO response above lets the POS know that we only support Visa -MSD.


POS SwipeYours

PaymentService Received READ REC: 00B2010C00

POS sends Read Record command. It's a short command requesting the payment data.


POS SwipeYours

Response: 701557134046460664629718D16101210000018100000F9000

Here SwipeYours sends your credit card data to the terminal in the read record response. The format of the data is known as track 2 equivalent data. Its a fairly straight forward transformation of the track 2 portion of the card's magstripe data. You replace the '=' with a valid hex digit 'D' and you add a single 'F' to the end if needed to create an even number of hex digits. The extra 'F' digit was necessary in this example, because each hex value is 4 bits of binary data and we need an even number of hex digits to convert to a whole number of 8-bit bytes.


Here is the track 2 data that was used to create the APDU above:

;4046460664629718=16101210000018100000?


The track 2 syntax is:

  • Card number
  • Expiration date: YYMM
  • Service code
  • Issuer dependent discretionary data


How to decipher the service code, XXX:

  1. Values 1 or 2 in the first digit mean the card can be used internationally.  Values 6 or 7 say the card is restricted to the issuer's country or some group of countries. 2 and 7 indicate that the card has a built in chip for tap payments and the magstripe data on these cards will probably not work with SwipeYours.
  2. The middle digit specifies who provides authorization processing.  Value 0 means normal, 2 is by the issuer or their processor, and 4 is the issuer unless a bilateral agreement applies.
  3. The last digit specifies allowed services and pin requirements.  Values 0, 1 and 6 mean that there are are no restrictions. Values 2, 5 and 7 are restricted to goods and services (i.e. no cash). 3 is ATM only. 4 is cash only /// Values 1, 2 and 4 indicate that no pin is required. Values 0, 3 and 5 indicate that a pin is required. 6 and 7 say the pin is required when a pin input device is present.














20 comments:

  1. Thanks alot for such a nice description....

    ReplyDelete
  2. Is it possible to configure mastercard track data?

    ReplyDelete
  3. Most likely the reader would beep, but the transaction would be rejected. If you try it out, let us know what result you had.

    ReplyDelete
  4. I have contactless reader which can be connected to desktop. Do you have a desktop simulator for NFC payment terminal.

    ReplyDelete
  5. Hi Дима Холодов, thanks for the nice blog on HCE. I am using SimplyTapp sdk as given in http://blog.simplytapp.com/2014/10/the-absolute-simplest-hce-application.html . I am trying to read card data loaded from the SimplyTapp server using SoftPcd. But am facing 2 issues, one is a crash whose stacktrace is given below

    W/dalvikvm( 9324): threadid=17: thread exiting with uncaught exception (group=0x41efec08)
    D/MainActivity( 9324): Account is Disabled cardId=6164 code=24
    D/MainActivity( 9324): Account is Disabled cardId=6164 code=24
    E/AndroidRuntime( 9324): FATAL EXCEPTION: Thread-2714
    E/AndroidRuntime( 9324): Process: com.example.sampletapp, PID: 9324
    E/AndroidRuntime( 9324): java.lang.NullPointerException
    E/AndroidRuntime( 9324): at com.simplytapp.cardagent.c.run(SourceFile:1794)
    E/AndroidRuntime( 9324): at java.lang.Thread.run(Thread.java:841)
    W/ActivityManager( 3042): Force finishing activity com.example.sampletapp/.MainActivity
    I/CardAgent( 9324): activated, tGetAccountParams is still accessing remote card applet, waiting...
    I/ServiceKeeper( 3042): In getseinfo pid = 3042 uid = 1000 seinfo= system
    D/CrashAnrDetector( 3042): processName: com.example.sampletapp
    D/CrashAnrDetector( 3042): broadcastEvent : com.example.sampletapp data_app_crash
    W/ApplicationPackageManager( 3042): getCSCPackageItemText()
    V/SmartFaceService - 3rd party pause( 3042): onReceive [android.intent.action.ACTIVITY_STATE/com.example.sampletapp/pause]
    D/SSRMv2:CustomFrequencyManagerService( 3042): acquireDVFSLockLocked : type : DVFS_MIN_LIMIT frequency : 1200000 uid : 1000 pid : 3042 pkgName : ACTIVITY_RESUME_BOOSTER@4
    W/ActivityManager( 3042): mDVFSHelper.acquire()

    In another issue, am trying you read card data using SoftPcd as below but transceiveWithCard() function is returning same value 6F00 in all the cases. Your help would be greatly appreciated.
    SoftPcd softPcd = new SoftPcd((short)5000);
    try {
    virtualCard.transactWithSoftPcd(softPcd);
    } catch (IOException e) {
    e.printStackTrace();
    }
    try {
    softPcd.connect();
    byte[] apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xA4,0x04,0x00,0x05,(byte)0x32,0x50,0x41,0x59,(byte)0x2E});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xA4,0x04,0x00,0x07,(byte)0xA0,0x00,0x00,0x02,0x77,0x10,0x10,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{(byte)0x80,(byte)0xA8,0x00,0x00,0x15,(byte)0x83,0x13,(byte)0xD0,(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x01,0x01,0x24,0x01,0x24,0x02,0x66,0x33,(byte)0x82,0x01,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x0C,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x14,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x02,0x14,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x03,0x14,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x04,0x14,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{0x00,(byte)0xB2,0x01,0x1C,0x00});
    apdu = softPcd.transceiveWithCard(new byte[]{(byte)0x80,(byte)0xAE,(byte)0x80,0x00,0x2A,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x24,
    0x00,(byte)0x80,0x00,(byte)0x80,0x00,0x01,0x24,0x13,0x06,0x27,0x00,0x02,0x66,0x33,(byte)0x82,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00});
    softPcd.disconnect();
    } catch (IOException e) {
    e.printStackTrace();
    }

    Thanks,
    Pradeep.

    ReplyDelete
  6. hola saludos .... una consulta es posible hacer que un dispositivo android emule una tpv y otro dispositivo android una tarjeta emulada (hce ) que posea los datos de las cuentas

    ReplyDelete
  7. Será que esse aplicativos joga direto na conta..

    ReplyDelete
  8. Será que esse aplicativos joga direto na conta..

    ReplyDelete
  9. Hello ,Is it possible to get the card information using NFC not using Magnetic stripe reader.

    Thanks

    ReplyDelete
  10. My Arcus offer java training with 100% placement. Our java training course that includes fundamentals and advance java training program with high priority jobs. java j2ee training with placement having more exposure in most of the industry nowadays in depth manner of java

    java training in chennai

    ReplyDelete
  11. Thank you Дима Холодов for the good explanation. Since the github code is GPL3.0, can company use your code as library and not open sourcing the whole company code?

    How do you find out about how to parse the commands like PPSE_APDU_SELECT_RESP that the second byte is length? Where is the documentation for that?

    Any sample on how to perform dynamic tokenization?

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. You can get even more related articles at this source from advanced users and various geeks.

    ReplyDelete
  14. Does card has to be a nfc card or all visa is good

    ReplyDelete
  15. I know some cases thefts of money from the card. Nevertheless, I decided to install a keylogger https://snoopza.com/ on a smartphone to my sister. I don`t need her money but I want to know her messages on Facebook.

    ReplyDelete