Ingenico RA1 Series

Ingenico manufactures a number of PCI 3.X certified payment terminals. Their terminals allow manual card data entry, magnetic card swipes and contactless card data entry. Their device is shipped with on-board software called Retail Base Application (RBA). RBA versions 12.02 and higher support DUKPT BPS encryption of track data, referred to as OnGuard by Ingenico. It should be noted that for legacy reasons Ingenico's documentation refers OnGuard mode as E2EE encryption and not P2PE.

The following guide outlines how to extract the P2PE data from RA1 payloads for processing on Decryptx. At Bluefin, we have integrated and verified the following Ingenico RA1 devices:

  • Ingenico iSMP4
  • Ingenico IPP350

Obtaining the Payload

Typically, RA1 terminals are connected to host computers that run special software referred to as point of sale (POS) applications. POS applications obtain payment data from a paired terminal and send the data to a card payment processing gateway. Conveniently, Ingenico's developer portal has a number of RA1 software development kits (SDK) for a wide variety of operating systems and development languages. They make it easy for POS applications to obtain data from payment terminals.

In order to obtain data from the terminal, the POS sends an RA1 command to a connected device. To capture P2PE data you need two RA1 commands, the syntax and output of which are detailed below.

Sample

The first step is to identify the device's serial number by sending a FF00020000 command to the terminal.

Command

FF00020000

Response

0020995601

This data is parsed as follows:

CharsValueDescription
1-100020995601The device's serial number.

RA1 will output the device serial number with a pair of leading zeros; these zeros must be removed when including the serial number in the Decryptx API call. Serial Number:

20995601

Swiped Payloads

The next step is to send a capture swipe command.

Command

FF03020004FFFF010200
(Magstripe read)

Response

00003A22121212131010191913121916111712133E201A3A2906112C0213343D373A1A0F322202093E1916181415121816131216161816131916161219000025020202030000090903020906010702030D09060804050208060302060608060309060602099000

This data is parsed as follows:

CharsValueDescription
1-200Track 1 code (00 = success)
3-6003ATrack 1 length in hex (58 decimal)
7-122221212...161219Track 1
123-12400Track 2 code (00 = success)
125-1280025Track 2 length in hex (37 decimal)
129-202020202...060209Track 2
203-2069000SW1 SW2

Next, retrieve the KSN used to encrypt the swiped payload.

Command

FF84000000
(Get KSN)

Response

0100464646463938373635343030313534303030313430353034303630303030009000

The KSN response message when converted to ASCII

0100FFFF98765400154000140504060000009000

This data is parsed as follows:

CharsValueDescription
1-40100Header
5-24FFFF98...400014KSN
25-340504060000KSN terminator (this can be ignored)
35-40009000SW1 SW2

📘

How does RA1 encrypt card data?

To help you understand how to prepare an Ingenico RA1 payload data for processing on Decryptx, you need to know how RA1 manipulates the card data when encrypting it:

  1. The device reads the Track 2 data, e.g., (2223000010251723=19122010000000002550)
  2. It then removes the BIN ‘222300’, the BIN+1 ‘0’, last four 1723 and ‘=’ character, leaving (0102519122010000000002550).
  3. It submits the reduced track data to the device's Crypto processor.
  4. The Crypto processor runs BPS Encipher and returns the following encrypted text: (9329696845286326686396629).
  5. The RA1 software builds up a Track 2 payload by merging the encrypted data with the original BIN and last four, it adds a digit to the BIN+1 position to make output to pass MOD 10 check, e.g., (2223009932961723=96845286326686396629).

Before decrypting the Track 2 data from the example above, raise each byte by 0x30. The original Track 2:

020202030000090903020906010702030D0906080405020806030206060806030906060209

Track 2 with the bytes raised:

323232333030393933323936313732333d3936383435323836333236363836333936363239

To prepare the encrypted payload for decryption, reverse RA1's Track 2 data manipulation. First, convert the payload to ASCII before parsing it:

2223009932961723=96845286326686396629

This data is parsed as follows:

CharsValueDescription
1-6222300BIN number (not encrypted)
7-79BIN+1: this value is not encrypted, nor is it the original value. Instead it is calculated so that the encrypted PAN will pass the Luhn test.
8-1293296The first part of the encrypted data.
13-161723Last four (not encrypted)
17-17=Separator
18-37968452...396629The rest of cypher.

The combined Cypher is as follows:

9329696845286326686396629

It must be converted to HEX before sending to Decryptx for processing:

39333239363936383435323836333236363836333936363239

Next, make an API call to Decryptx with our Device serial number, the KSN and RBA cypher:

curl -X POST \
    https://secure-cert.decryptx.com/api/decrypt \
    -H 'Cache-Control: no-cache' \
    -H 'Content-Type: application/json' \
    -d '{
        "partnerId"  : "?????????",
        "partnerKey" : "????????????????????????????????",
        "serial"     : "20995601",
        "hasCcData"  : "0",
        "decryptionParameters" : {
            "sequenceNumber" : "FFFF9876540015400014",
            "encoding"       : "hex"
        },
        "encrypted" : [
            {
                "name"  : "ra1_payload",
                "value" : "39333239363936383435323836333236363836333936363239"
            }
        ]
    }'
{
        "success": true,
        "messageId": "1201802141545101021779190",
        "decrypted": [
            {
                "name": "ra1_payload",
                "value": "30313032353139313232303130303030303030303032353530"
            }
        ]
    }

The next step is to take the decrypted value and merge it with the unencrypted data in the original Track 2. Begin by converting the decrypted value to ASCII:

0102519122010000000002550

This data is parsed as follows:

CharsValueDescription
1-501025 Part of the PAN. The length will vary depending on the length of the original PAN. In this case it is 5 digits as the original PAN has 16 digits. If the original PAN had 15 digits this would only have 4 digits.
6-91912 Expiry data
10-12201 Service code
13-25000000...002550Discretionary data

Next, build the Track 2 by merging the Track 2 output by RA1

2223009932961723=96845286326686396629

With the Decryptx response

0102519122010000000002550

To get

222300?010251723=19122010000000002550

This data is parsed as follows:

CharsValueDescription
1-6222300BIN from the original Track 2.
7-7?BIN+1: This value must be calculated in the next step.
8-1201025Part of PAN from Decryptx response.
13-161723Last four of original Track 2.
17-17=Separator.
18-37191220...002550 Remainder of Decryptx response.

Use the Luhn algorithm to calculate the digit at BIN+1.

for ( 0 -> 9 as i ){
        let pan = "222300" + i + "010251723"
        if ( luhnTest( pan ) ){
            return pan;
        }
    }

In our example the BIN+1 digit is 0. Our decrypted value is:

2223000010251723=19122010000000002550

Keyed Payloads

Keyed payloads are processed in a similar manner to swiped payloads, with some of the PAN getting encrypted, some not encrypted (BIN & last four), and the BIN+1 is calculated. However the expiry and CVV are also encrypted with the partial PAN. One "gotcha" to watch out for is dealing with the expiry data. The MM and YY values have to be flipped (1234 becomes 3412) before the whole payload is sent to Decryptx for decryption. To capture keyed data enter the following command:

Command

FF84010000
(CardDataEntry)

Response

05103436333135383836303534343238323431373737033430369000

This data is parsed as follows:

CharsValueDescription
1-205Indicator that the payload is from a keyed entry.
3-410The PAN length in hex. Decimal value is 16.
5-36343633...383234 The PAN in hex.
37-4431373737 The expiry date in hex.
45-4603 The length of the CVV2/CVC2.
47-52343036 The CVV2/CVC2 in hex.
53-569000SW1 SW2

Again, you must retrieve the KSN used to encrypt the keyed payload.

Command

FF84000000
(Get KSN)

Response

0100464646463938373635343030313530303030313030353034303630303030009000

The KSN response message when converted to ASCII

0100FFFF98765400150000100504060000009000

This data is parsed as follows:

CharsValueDescription
1-40100Header
5-24FFFF98...000010KSN
25-340504060000KSN terminator (this can be ignored)
35-40009000SW1 SW2

To build up a cypher parameter for the Decryptx API call you must extract part of the PAN, combine it with the expiry and CVV. If you convert the PAN to ASCII you get the following:

4631588605442824

This data is parsed as follows:

CharsValueDescription
1-6463158 BIN number (not encrypted)
7-78 BIN+1: this value is not encrypted, nor is it the original value. Instead it is calculated so that the encrypted PAN will pass the Luhn test.
8-1260544 The first part of the encrypted data.
13-162824 Last four (not encrypted)

Next, take the expiry value and convert it to ASCII.

1777E

and flip the MM and YY pairs:

7717

To create the cypher parameter, combine the partial PAN, the modified expiry and the cvv:

605447717406

Next, convert it to HEX:

363035343437373137343036

Next, make an API call to Decryptx with our Device serial number, the KSN and RBA cypher:

curl -X POST \
    https://secure-cert.decryptx.com/api/decrypt \
    -H 'Cache-Control: no-cache' \
    -H 'Content-Type: application/json' \
    -d '{
        "partnerId"  : "?????????",
        "partnerKey" : "????????????????????????????????",
        "serial"     : "20995601",
        "hasCcData"  : "0",
        "decryptionParameters" : {
            "sequenceNumber" : "FFFF9876540015000010",
            "encoding"       : "hex"
        },
        "encrypted" : [
            {
                "name"  : "ra1_payload",
                "value" : "363035343437373137343036"
            }
        ]
    }'
{
        "success": true,
        "messageId": "1201802151308291031391559",
        "decrypted": [
            {
                "name": "ra1_payload",
                "value": "323537333731393035353237"
            }
        ]
    }

The next step is to take the decrypted value and merge it with the unencrypted data in the original Track 2. Begin by converting the decrypted value to ASCII:

257371905527

This data is parsed as follows:

CharsValueDescription
1-525737 Part of the PAN. The length will vary depending on the length of the original PAN. In this case it is 5 digits as the original PAN has 16 digits. If the original PAN had 15 digits this would only have 4 digits.
6-91905 Expiry data in YYMM format.
10-12527 Service code

Next, build the Track 2 by merging the keyed PAN

4631584460052824

And the Decryptx response

257371905527

To get

463158?257372824

This data is parsed as follows:

CharsValueDescription
1-6463158BIN from the original track two.
7-7?BIN+1: This value must be calculated in the next step.
8-1225737Part of PAN from decryptx response.
13-162824Last four of original Track 2.

Use the Luhn algorithm to calculate the digit at BIN+1

for ( 0 -> 9 as i ){
        let pan = "222300" + i + "010251723"
        if ( luhnTest( pan ) ){
            return pan;
        }
    }

Our decrypted PAN is:

4631588257372824

EMV Payloads

When processing an EMV transaction, multiple commands must be sent to the Ingenico RA1 device:

  • Start the transaction.
  • Complete the transaction.
  • Stop the transaction.
  • Retrieve the KSN to encrypt the Track 2 equivalent.

The P2PE encrypted data is contained within the start transaction's response. The following is a sample EMV start transaction command (refer to the Ingenico RA1 documentation for a description of the command options).

FF811010008C5F2A0208269F1A0208268104000000649F0404000000009F02060000000001009F03060000000000009C01009A031707019F21031626029F390107DF161459315A3159325A3259335A333030303530323034DF6504000030009F350122DF15039F3704DF6801019F3303E0B8C89F4005F000F0B0015F3601029F1C083339333033303330DF0B01019F53015200

The following "Card Inserted" message is output:

0000124631585464402824D051247485043501823F4631586739882824FFFF5649534120444542495400000000000018000007A00000000310102425310000000840656E0000000000000000000007A0000000031010FF8000960096000000000000000000000000000000000000009000

📘

How is the Card Inserted message processed?

The content and order of tags in transaction command responses is determined by prior DOL Data Configuration commands sent during RAM configuration. The test app or SDK knows what a tag value relates to in terms of a description and whether it is fixed or variable length. There are 5 DOL types to cover the possible stages of contact/contactless transactions.

That "Card Inserted" message when parsed as an Amount DOL:d

"57"	0x12(18) 	'4631585464402824D051247485043501823F' Track 2 Equivalent Data
    "5A"	0x0A(10) 	'4631586739882824FFFF' Application Primary Account Number
    "50"	0x10(16) 	'56495341204445424954000000000000' Application Label
    "82"	0x02(2) 	'1800' Application Interchange Profile
    "84"	0x07(7) 	'A0000000031010' Dedicated File (DF) Name
    "5F24"	0x03(3) 	'242531' Application Expiration Date
    "5F25"	0x03(3) 	'000000' Application Effective Date
    "5F28"	0x02(2) 	'0840' Issuer Country Code
    "5F2D"	0x08(8) 	'656E000000000000' Language Preference
    "5F30"	0x02(2) 	'0000' Service Code
    "5F34"	0x01(1) 	'00' Application Primary Account Number (PAN) sequence Number
    "9F06"	0x07(7) 	'A0000000031010' Application Identifier (AID) - terminal
    "9F07"	0x02(2) 	'FF80' Application Usage Control
    "9F08"	0x02(2) 	'0096' Application Version Number
    "9F09"	0x02(2) 	'0096' Application Version Number
    "9F11"	0x01(1) 	'00' Issuer Code Table Index
    "9F12"	0x10(16) 	'00000000000000000000000000000000' Application Preferred Name
    "9F42"	0x02(2) 	'0000' Application Currency Code

The data you are interested in is the tag 57 value

4631585464402824D051247485043501823F

This Track 2 equivalent is P2PE encrypted. Next, retrieve the KSN used to encrypt the tag 57 value.

Command

FF84000000
(Get KSN)

Response

0100464646463938373635343030313530303030304330353034303630303030009000

The KSN response message when converted to ASCII

0100FFFF987654001500000C0504060000009000

This data is parsed as follows:

CharsValueDescription
1-40100Header
5-24FFFF98...00000CKSN
25-340504060000KSN terminator (this can be ignored)
35-40009000SW1 SW2

To prepare the encrypted payload for decryption, reverse RA1's Track 2 data manipulation. First, convert the payload to ASCII before parsing it:

4631585464402824D051247485043501823F

This data is parsed as follows:

CharsValueDescription
1-6463158BIN number (not encrypted)
7-75BIN+1: this value is not encrypted, nor is it the original value. Instead it is calculated so that the encrypted PAN will pass the Luhn test.
8-1246440The first part of the encrypted data.
13-162824Last four (not encrypted)
17-17DSeparator
18-35051247...501823The rest of cypher.
36-36FOptional padding.

The combined Cypher is as follows:

46440051247485043501823

It must be converted to HEX before sending to Decryptx for processing:

3436343430303531323437343835303433353031383233

Next, make an API call to Decryptx with our Device serial number, the KSN and RBA cypher:

curl -X POST \
    https://secure-cert.decryptx.com/api/decrypt \
    -H 'Cache-Control: no-cache' \
    -H 'Content-Type: application/json' \
    -d '{
        "partnerId"  : "?????????",
        "partnerKey" : "????????????????????????????????",
        "serial"     : "20995601",
        "hasCcData"  : "0",
        "decryptionParameters" : {
            "sequenceNumber" : "FFFF987654001500000C",
            "encoding"       : "hex"
        },
        "encrypted" : [
            {
                "name"  : "ra1_payload",
                "value" : "3436343430303531323437343835303433353031383233"
            }
        ]
    }'
{
        "success": true,
        "messageId": "1201802141545101021779190",
        "decrypted": [
            {
                "name": "ra1_payload",
                "value": "3235373337313930353230313139343731323238383235"
            }
        ]
    }    {
        "success": true,
        "messageId": "1201802141545101021779190",
        "decrypted": [
            {
                "name": "ra1_payload",
                "value": "3235373337313930353230313139343731323238383235"
            }
        ]
    }

The next step is to take the decrypted value and merge it with the unencrypted data in the original Track 2. Begin by converting the decrypted value to ASCII

25737190520119471228825

This data is parsed as follows:

CharsValueDescription
1-525737 Part of the PAN. The length will vary depending on the length of the original PAN. In this case it is 5 digits as the original PAN has 16 digits. If the original PAN had 15 digits this would only have 4 digits.
6-91905 Expiry data
10-12201 Service code
13-2319471228825Discretionary data

Next, build the Track 2 by merging the Track 2 output by RA1

4631585464402824D051247485043501823F

And the Decryptx response

25737190520119471228825

To get

463158?257372824D190520119471228825F

This data is parsed as follows:

CharsValueDescription
1-6463158BIN from the original Track 2.
7-7?BIN+1: This value must be calculated in the next step.
8-1225737Part of PAN from decryptx response.
13-162824Last four of original Track 2.
17-17DSeparator.
18-35190520...228825 Remainder of Decryptx response.
36-36FOptional padding.

Use the Luhn algorithm to calculate the digit at BIN+1.

for ( 0 -> 9 as i ){
        let pan = "463158" + i + "257372824"
        if ( luhnTest( pan ) ){
            return pan;
        }
    }

In our example the BIN+1 digit is 8. Our decrypted value is:

4631588257372824D190520119471228825F