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:
Chars | Value | Description |
---|---|---|
1-10 | 0020995601 | The 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:
Chars | Value | Description |
---|---|---|
1-2 | 00 | Track 1 code (00 = success) |
3-6 | 003A | Track 1 length in hex (58 decimal) |
7-122 | 221212...161219 | Track 1 |
123-124 | 00 | Track 2 code (00 = success) |
125-128 | 0025 | Track 2 length in hex (37 decimal) |
129-202 | 020202...060209 | Track 2 |
203-206 | 9000 | SW1 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:
Chars | Value | Description |
---|---|---|
1-4 | 0100 | Header |
5-24 | FFFF98...400014 | KSN |
25-34 | 0504060000 | KSN terminator (this can be ignored) |
35-40 | 009000 | SW1 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:
- The device reads the Track 2 data, e.g.,
(2223000010251723=19122010000000002550)
- It then removes the BIN ‘222300’, the BIN+1 ‘0’, last four
1723
and ‘=’ character, leaving(0102519122010000000002550)
.- It submits the reduced track data to the device's Crypto processor.
- The Crypto processor runs BPS Encipher and returns the following encrypted text:
(9329696845286326686396629)
.- 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:
Chars | Value | Description |
---|---|---|
1-6 | 222300 | BIN number (not encrypted) |
7-7 | 9 | 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-12 | 93296 | The first part of the encrypted data. |
13-16 | 1723 | Last four (not encrypted) |
17-17 | = | Separator |
18-37 | 968452...396629 | The 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:
Chars | Value | Description |
---|---|---|
1-5 | 01025 | 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-9 | 1912 | Expiry data |
10-12 | 201 | Service code |
13-25 | 000000...002550 | Discretionary 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:
Chars | Value | Description |
---|---|---|
1-6 | 222300 | BIN from the original Track 2. |
7-7 | ? | BIN+1: This value must be calculated in the next step. |
8-12 | 01025 | Part of PAN from Decryptx response. |
13-16 | 1723 | Last four of original Track 2. |
17-17 | = | Separator. |
18-37 | 191220...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:
Chars | Value | Description |
---|---|---|
1-2 | 05 | Indicator that the payload is from a keyed entry. |
3-4 | 10 | The PAN length in hex. Decimal value is 16. |
5-36 | 343633...383234 | The PAN in hex. |
37-44 | 31373737 | The expiry date in hex. |
45-46 | 03 | The length of the CVV2/CVC2. |
47-52 | 343036 | The CVV2/CVC2 in hex. |
53-56 | 9000 | SW1 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:
Chars | Value | Description |
---|---|---|
1-4 | 0100 | Header |
5-24 | FFFF98...000010 | KSN |
25-34 | 0504060000 | KSN terminator (this can be ignored) |
35-40 | 009000 | SW1 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:
Chars | Value | Description |
---|---|---|
1-6 | 463158 | BIN number (not encrypted) |
7-7 | 8 | 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-12 | 60544 | The first part of the encrypted data. |
13-16 | 2824 | 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:
Chars | Value | Description |
---|---|---|
1-5 | 25737 | 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-9 | 1905 | Expiry data in YYMM format. |
10-12 | 527 | 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:
Chars | Value | Description |
---|---|---|
1-6 | 463158 | BIN from the original track two. |
7-7 | ? | BIN+1: This value must be calculated in the next step. |
8-12 | 25737 | Part of PAN from decryptx response. |
13-16 | 2824 | Last 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:
Chars | Value | Description |
---|---|---|
1-4 | 0100 | Header |
5-24 | FFFF98...00000C | KSN |
25-34 | 0504060000 | KSN terminator (this can be ignored) |
35-40 | 009000 | SW1 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:
Chars | Value | Description |
---|---|---|
1-6 | 463158 | BIN number (not encrypted) |
7-7 | 5 | 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-12 | 46440 | The first part of the encrypted data. |
13-16 | 2824 | Last four (not encrypted) |
17-17 | D | Separator |
18-35 | 051247...501823 | The rest of cypher. |
36-36 | F | Optional 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:
Chars | Value | Description |
---|---|---|
1-5 | 25737 | 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-9 | 1905 | Expiry data |
10-12 | 201 | Service code |
13-23 | 19471228825 | Discretionary 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:
Chars | Value | Description |
---|---|---|
1-6 | 463158 | BIN from the original Track 2. |
7-7 | ? | BIN+1: This value must be calculated in the next step. |
8-12 | 25737 | Part of PAN from decryptx response. |
13-16 | 2824 | Last four of original Track 2. |
17-17 | D | Separator. |
18-35 | 190520...228825 | Remainder of Decryptx response. |
36-36 | F | Optional 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
Updated 11 months ago