Ingenico RBA

How to extract P2PE data from Ingenico RBA payloads for processing on the Decryptx Parser.

Our Parser can process payloads from Ingenico RBA devices that produce P2PE payloads. RBA devices include the iPP 320, iPP 350, iSC 250, iSC Touch 250, and iSC Touch 480. These devices support manual card data entry, magnetic card swipes, and contactless card data entry.

Typically, Ingenico terminals are connected to a host computer that runs a point of sale (POS) application. The vendor's developer portal supplies software development kits (SDK) for a wide variety of operating systems and development languages. They make it easy for the POS application to obtain data from the payment terminal.

In this guide we include sample code that uses Ingenico's Android SDK to extract a P2PE secured payload from an RBA terminal. Ingenico provides similar SDKs in pure Java, Objective-C, and a number of other languages. While the programming languages are different, the software uses a similar pattern when extracting data from the terminal, i.e., the SDK/POS sends async commands to the terminal. The commands are sent via an instance of RBA_API class. Other code listens for responses to act upon.

First, identify the device's serial number by sending a Health Check (08) command to the terminal:

//Send the command via the RBA_API object.
ERROR_ID result = RBA_API.ProcessMessage( MESSAGE_ID.M08_HEALTH_STAT );

//check to see if the result of the command was a success or not.
if ( result == ERROR_ID.RESULT_SUCCESS ) {
    logData("Successfully Sent 87 command");
}
else {
    logData("Failed to Send 87 command: Error = " + result);
}

In the listener code, extract the serial number from the response and store it in the serialNumber variable for later use:

final String serialNumber =
  RBA_API.GetParam(PARAMETER_ID.P08_RES_SERIAL_NUMBER)

Obtaining the Payload

Next, send an 87 command to the terminal to initialise a card data capture and encryption. The following snippet of Android code updates the terminal text and sends the 87 command to the terminal:

//set the text to appear on the terminal screen.
RBA_API.SetParam( PARAMETER_ID.P87_REQ_PROMPT_INDEX, "Please swipe card." );

//Send the command via the RBA_API object.
ERROR_ID result = RBA_API.ProcessMessage( MESSAGE_ID.M87_E2EE_CARD_READ );

//check to see if the result of the command was a success or not. 
if ( result == ERROR_ID.RESULT_SUCCESS ) {
    logData("Successfully Sent 87 command");
}
else {
    logData("Failed to Send 87 command: Error = " + result);
}

The following code processes the response and extracts the payload:

String exitType = RBA_API.GetParam( PARAMETER_ID.P87_RES_EXIT_TYPE );
switch ( Integer.parseInt( exitType ) ) {
    case 0: {
        //Successful read and P2PE encryption
        String source   = RBA_API.GetParam( PARAMETER_ID.P87_RES_CARD_SOURCE );
        String cardData = RBA_API.GetParam( PARAMETER_ID.P87_RES_CARD_DATA   );
        logData( "Card Source = " + source   );
        logData( "Card Data   = " + cardData );
        break;
    }
    case 1:     logData( "Bad Read" );              break;
    case 2:     logData( "Cancelled" );             break;
    case 3:     logData( "Button Pressed" );        break;
    case 7:     logData( "Encryption Failed" );     break;
    case 9:     logData( "Declined" );              break;
    default:    logData( "ERROR" );                 break;
}

Processing Payloads

The cardData variable contains the payload data that you want to use in your API call.

54152444441612212101912TEST/BLUEFIN1B0B0229000000000000020114334787735642891651=726961371397062832AF86BB9DB92C98416AAB5BCA769D565A96C1E5C07F1D49A912C9919DBD3EA0661DF20CAC633BC330ECF753994278F50F56F7A2CE0C7212BAACFDED1632B98BE3EC8

To use this payload with the Parser, post it with your Bluefin credentials and the device's serial number to our Parser endpoint:

curl 'https://cert-parser.decryptx.com/api/decrypt/parser' \
    -X POST \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    -d '{
            "partnerId"     : "?????????",
            "partnerKey"    : "ef1ad938150fb15a1384b883a104ce70",
            "reference"     : "723f57e1-e9c8-48cb-81d9-547ad2b76435",
            "deviceType"    : "ingenico-rba",
            "deviceSerial"  : "80612860",
            "devicePayload" : "54152444441612212101912TEST/BLUEFIN1B0B0229000000000000020114334787735642891651=726961371397062832AF86BB9DB92C98416AAB5BCA769D565A96C1E5C07F1D49A912C9919DBD3EA0661DF20CAC633BC330ECF753994278F50F56F7A2CE0C7212BAACFDED1632B98BE3EC8"
        }'

If the API call is successful a JSON response object similar to the following is returned:

{
  "success"   : true,
  "messageId" : "1201703221545061032173045",
  "reference" : "723f57e1-e9c8-48cb-81d9-547ad2b76435",
  "meta": {
    "device" : "INGENICO",
    "serial" : "80612860",
    "mode"   : "swiped"
  },
  "track2": {
    "decrypted" : "34313532343434343434343434343432323132313031313233343536373839",
    "encoding"  : "hex",
    "length"    : 33,
    "ascii"     : ";5415244444444444=2212101123456789?",
    "masked"    : ";541524******4444=2212************?"
  },
  "extracted": {
    "PAN"       : "5415244444444444",
    "FirstName" : "BLUEFIN",
    "Surname"   : "TEST",
    "EXPY"      : "1222",
    "ServiceCode"   : "101",
    "Discretionary" : "123456789"
  }
}

RBA Test Application

It is possible to extract payload data from an Ingenico device by using the vendor's RBA Test Application. To capture a payload with the test application execute an 87 command. The output from the terminal is displayed on the Test Application. Instead of the one byte characters for a) start of transmission, b) end of transmission, c) field separator and d) LRC check sum, the response will contain the following text elements [STX], [ETX], [FC] and [LRC]. For example,

[STX]87.0[FS]41249399901612212101912TEST/BLUEFIN1BFFFF99999900F660000B0114331089645004140780=52138380040406783299B50C91A3B8A8302DB5B68F36AAE851960E91C78B1AA699A986957236BB6FAD69F7047F06FF046FF61B1A020BD2016814A2E402305C089BABA1214883E15FB1698[ETX][LRC]

While the encrypted payload is only a subset of this response string, you can use the whole string with the Parser. The Parser will identify the relevant data and extract it from the full string.

EMV Payloads

After an Ingenico RBA device has processed an EMV transaction it will output a payload containing the EMV tag names, the value length and tag values. This payload is similar to the standard EMV TLV string. However, it has additional markers to denote if the value is hexadecimal (h) or ASCII (a); it separates the tag name, length and value with a colon (:) character; and, it precedes the tag name with a T. To process the transaction with the Parser, you may either parse the payload and pass the FFIF in the devicePayload parameter or simply pass the whole payload as the devicePayload parameter.

The following is a sample Ingenico RBA EMV payload:

T4F:07:hA0000000041010T50:0A:aMasterCardT57:13:h5413330000004111D251220100000000000000T5A:08:h5413330000004111T5F20:1A:aDI Test/Card 06 T5F24:03:h251231T5F28:02:h0840T5F2D:02:aenT5F30:02:h0201T5F34:01:h01T9F07:02:hFF00T9F11:01:h01T9F12:10:h4D617374657243617264437265646974T9F1A:02:h0840T9F1B:04:h00002710T9F1E:08:a81307672T9F42:02:h0840TFF1D:10:a5413330000004111TFF1F:DD:a541333411116125122019001B000228000000008001180114376248475596474612=66092625902428597688325E5FF48DC371B11A809720226B53C20996002D91C8F524C3A17C9335A17A387D5743DB8EC29B6F111F015BF1E9A76AC41F4ADC511E315AE17DB8B530A29E2DF64

The following Parser API call sends the complete EMV string in the devicePayload parameter:

curl 'https://cert-parser.decryptx.com/api/decrypt/parser' \
    -X POST \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    -d '{
            "partnerId"     : "?????????",
            "partnerKey"    : "ef1ad938150fb15a1384b883a104ce70",
            "reference"     : "723f57e1-e9c8-48cb-81d9-547ad2b76435",
            "deviceType"    : "ingenico-rba",
            "deviceSerial"  : "80612860",
            "devicePayload" : "T4F:07:hA0000000041010T50:0A:aMasterCardT57:13:h5413330000004111D251220100000000000000T5A:08:h5413330000004111T5F20:1A:aDI Test/Card 06           T5F24:03:h251231T5F28:02:h0840T5F2D:02:aenT5F30:02:h0201T5F34:01:h01T9F07:02:hFF00T9F11:01:h01T9F12:10:h4D617374657243617264437265646974T9F1A:02:h0840T9F1B:04:h00002710T9F1E:08:a81307672T9F42:02:h0840TFF1D:10:a5413330000004111TFF1F:DD:a541333411116125122019001B000228000000008001180114376248475596474612=66092625902428597688325E5FF48DC371B11A809720226B53C20996002D91C8F524C3A17C9335A17A387D5743DB8EC29B6F111F015BF1E9A76AC41F4ADC511E315AE17DB8B530A29E2DF64"
        }'

Response:

{
    "success"   : true,
    "messageId" : "1201805011508401001681246",
    "meta": {
        "device" : "INGENICO",
        "serial" : "80612860",
        "mode"   : "emv"
    },
    "track2": {
        "decrypted" : "3431333333303038393630343131313235313232303130313233343039313732303239",
        "encoding"  : "hex",
        "length"    : 37,
        "ascii"     : ";5413330089604111=25122010123409172029?",
        "masked"    : ";541333******4111=2512****************?"
    },
    "extracted": {
        "PAN"  : "5413330089604111",
        "EXPY" : "1225",
        "ServiceCode"   : "201",
        "Discretionary" : "0123409172029"
    }
}

To extract the FF1F value you must search the payload for the TFF1F marker, then parse the length value that follows it (sandwiched between the two :), discard the a marker that precedes the value (denotes that the value is ASCII). In this example the length is DD hexadecimal or 221 in decimal. Once you discard the a marker, grab the next 221 characters and use that in your API call to the Parser.

The TFF1F value from our example:

541333411116125122019001B000228000000008001180114376248475596474612=66092625902428597688325E5FF48DC371B11A809720226B53C20996002D91C8F524C3A17C9335A17A387D5743DB8EC29B6F111F015BF1E9A76AC41F4ADC511E315AE17DB8B530A29E2DF64

Sample API call:

curl 'https://cert-parser.decryptx.com/api/decrypt/parser' \
    -X POST \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    -d '{
            "partnerId"     : "?????????",
            "partnerKey"    : "ef1ad938150fb15a1384b883a104ce70",
            "reference"     : "723f57e1-e9c8-48cb-81d9-547ad2b76435",
            "deviceType"    : "ingenico-rba",
            "deviceSerial"  : "80612860",
            "devicePayload" : "541333411116125122019001B000228000000008001180114376248475596474612=66092625902428597688325E5FF48DC371B11A809720226B53C20996002D91C8F524C3A17C9335A17A387D5743DB8EC29B6F111F015BF1E9A76AC41F4ADC511E315AE17DB8B530A29E2DF64"
        }'

Response:

{
    "success"   : true,
    "messageId" : "1201805011535321001792041",
    "meta": {
        "device" : "INGENICO",
        "serial" : "20995601",
        "mode"   : "emv"
    },
    "track2": {
        "decrypted" : "3431333333303038393630343131313235313232303130313233343039313732303239",
        "encoding"  : "hex",
        "length"    : 37,
        "ascii"     : ";5413330089604111=25122010123409172029?",
        "masked"    : ";541333******4111=2512****************?"
    },
    "extracted": {
        "PAN"  : "5413330089604111",
        "EXPY" : "1225",
        "ServiceCode"   : "201",
        "Discretionary" : "0123409172029"
    }
}