Documentation Menu
Redirect Model – Digest Calculation

Digest is the safety valve for the transactions between Company and Cardlink e- Commerce. Digest is one of the fields that the payment page sends and certifies the safe data transferring between the company and the Bank.

 

Requirements for Digest creation:

The field values that the POST form sends (post_fields_values).

Based on the values of the payment page fields, the company needs to create a string with all the field values sent by payment page in the bank system.

Concatenate all the values of all the possible fields listed in the table, the same order as parameters are listed in Payment page fields table.

If a parameter is omitted, empty string is concatenated.

The string must be encoded using UTF – 8 char encoding. This can be achieved by using the functions provided by the language that implements the solution (eg utf8_encode for PHP or Encoding.Convert for .NET).

 

The SHARED SECRET

The bank communicates to every merchant a unique code which is called SHARED SECRET. The SHARED SECRET must be included at the end of the previous string.

3) The base64 and sha-256 functions.

Digest in the request POST (and in the return POST) is calculated by the following rule:

 

  1. Concatenate all the values of all the possible fields listed in the table, the same order as parameters are listed in Payment page fields table.
  2. Add SHARED SECRET
  3. Encryption and Encoding using base64 and sha 256* functions
    • Calculate SHA256 digest of step 1 (using of UTF-8 char encoding when converting string to bytes).
    • Return the SHA256 digest.
    • Encode digest bytes with Base64 encoding.

*For Recurring notification POST, if version=2 is missing, use SHA1

Digest=base64( sha256( utf8bytes(value1|value2|…|secret) ) )

Note: ‘|’ indicates concatenation of data in formula and must not be added to data.

 

Never implement the digest calculation in browser using javascipt or similar as this way you expose your shared secret to the world. Only implement it in server side executed code as (jsp/servlet/asp/php etc).

 

The parameters that the merchant must include in post request are the following:

The sequence of those parameters will be used to calculate the digest parameter in the next steps

Counter  Field (HTTP POST parameter)  Required / Optional  Description 
  1.  
version  R  Value 2 

  2.  

mid  R  Merchant id supplied (integer number) will be supplied to merchant, max length 30 
3. lang  O  Language selection for payment page (ISO 639-1 language code  en, fi, sv…) 
4. deviceCategory  O  Optional user device category (default 0 www browser, 1 mobile browser) 
5. orderid  R  Unique merchant shop order id provided by merchant shop max length 50 chars (string 1..50 – only letters and numbers are accepted with no any space between them). For recurring transactions, max length 45 chars.
6. orderDesc  R  Order description text (string 1..128 – special characters are accepted ) 
7.  orderAmount  R  Order amount (decimal number >0.0) max length 15 with decimal point 
8. currency  R  Order amount currency (string 3 ISO ISO 4217 alphabetic code (EUR)) 
9. payerEmail  R Order payer email address (string 1..64) 
10. payerPhone  O Order payer phone number
Format
• cc: 1–3 characters
• subscriber: variable, maximum 15 characters
11. billCountry  R  Billing address country code (string 2 ISO 3166-1-alpha-2 code (GR,US, FI, GB)) 

For Kosovo, use Serbia’s country code RS

12. billState  O  Billing address state (str 2 3166-2 country subdivision code)this value only applies to countries that have states (e.g USA). For Greece, strongly recommended to be omitted
13. billZip  R  Billing address zip code (string..16) 
14. billCity  R  Billing address city (string..50) 
15. billAddress  R  Billing address street (string..50) 
16. weight  O  Order shipping weight (kg) if item is shippable and shipping needs to be calculated by Cardlink Payment Gateway (decimal number >0) max length 12 with decimal point) 
17. dimensions  O  Order shipping dimensions (mm) in format width:height:depth for example a box 200:200:200 (string..25) can be used for shipping calculation if implemented so 
18. shipCountry  O/R  Shipping address country code (string 2 ISO 3166-1-alpha-2 code (GR,US, FI, GB)). Recommended when parameter weight or dimensions are present or when shipping of goods has to be made.
19. shipState   O/R  Shipping address state (string..50). Recommended when parameter weight or dimensions are present or when shipping of goods has to be made. This value only applies to countries that have states (e.g USA). For Greece, strongly recommended to be omitted.
20.  shipZip  O/R  Shipping address zip code (string..16). Recommended when parameter weight or  dimensions are present or when shipping of goods has to be made.
21. shipCity  O/R  Shipping address city (string..50). Recommended when parameter weight or dimensions are present or when shipping of goods has to be made.
22.  shipAddress  O/R  Shipping address street (string..50) Recommended when parameter weight or dimensions are present or when shipping of goods has to be made.
23. addFraudScore  O  Incoming starting risk score (integer) max length 12 
24. maxPayRetries  O  Maximum payment retries allowed before user is sent back to merchant, overrides specific profile setting if present (integer) max length 2 
25. reject3dsU  O  Should 3-D Secure return U status, merchant has option of continuing the transaction without liability shift or reject the transaction. >If this value is true, the transaction will not be accepted. (string 1 Y/N) 
26. payMethod  O  For pre selection of payment method. Paymethod id, can be used to preselect payment method at merchant site, so user 

cannot select other payment method later (string..20), exact values  will  depend  of  implemented  methods  on  service provider side. 

27. trType  O  Optional transaction type default assumed payment, valid  values 1 – payment, 2 – pre authorization (applicable only to card payments only) 
28. extInstallmentoffset  O  Optional. In case installments are supported by the processing system then this parameter of installments can be used to indicate initial offset in months when first payment will be submitted (by acquirer). Applicable for card payments only. Integer max length 3. Currently, should have value 0. 
29. extInstallmentperiod  O/R  Optional, required in case previous parameter is present. In case installments are supported by the processing system then 

this parameter of installments is used to indicate the number of payments/months the merchant requests for installments. 

Applicable for card payments only. Value must be >1. Max length 3 

Installment parameters and recurring parameters together are not allowed on same request 

30.

extRecurringfrequency  O  Optional. In case recurring payments are supported by the processing system then this parameter can be used to indicate frequency of recurring payments, defines minimum number of days between any two subsequent payments. The number of days equal to 28 is special value indicating that transactions are 

to be initiated on monthly basis. Applicable for card payments only. Max length 3 

31. extRecurringenddate  O/R  Optional, required in case previous parameter is present. In case recurring payments are supported by the processing 

system then this parameter can be used to indicate date after which recurring ends and no more transactions are initiated. The format is YYYYMMDD. 

Applicable for card payments only. 

Installment parameters and recurring parameters together are not allowed on same request. 

32. blockScore  O  Optional block score parameter that will be used to block the transaction if transaction riskScore reaches this value or above. (Positive Integer numbermax length 9. 
33. cssUrl  O  The absolute or relative (to Cardlink Payment Gateway location on server) url of custom CSS stylesheet, to be used to display payment page  styles.  (string..128)  Note:  if  absolute  and payment page is SSL secured make sure the url is also SSL secured as browsers will not show unsecure element object warning. 
34. confirmUrl  R  Confirmation url where to send payment confirmation in case payment was successful (string..128) 
35. cancelUrl  R  Cancel url where to send payment feedback in case payment has failed or was canceled by user (string..128) 
36. var1  O  Optional merchant and acquirer agreed free variable type  string ..255 
37. var2  O  Optional merchant and acquirer agreed free variable type string ..255 
38. var3  O  Optional merchant and acquirer agreed free variable type string ..255 
39. var4  O  Optional merchant and acquirer agreed free variable type string ..255 
40.  var5  O  Optional merchant and acquirer agreed free variable type string ..255 
41.  var6  O  Optional merchant and acquirer agreed free variable type string ..255 
42. var7  O  Optional merchant and acquirer agreed free variable type string ..255 
43. var8  O  Optional merchant and acquirer agreed free variable type string ..255 
44. var9  O  Optional merchant and acquirer agreed free variable type string ..255 
45. digest  R  Message digest to ensure and verify message security and integrity.  SHA256  digest  of  all  the  field  values  above concatenated together with the shared secret (see section Calculation of the Digest). 

 

if you have trouble calculating the digest, please use the tool.

Example
In the below example of Sale Transaction, the digest value sent was calculated as «NCGHNiNtLXY/aMLGSQrogsjlPtPucqQF6NAk1y0+FCg=». According to the digest calculation rules this value is delivered as follows:

HTML
<form id="form1" accept-charset="UTF-8" action=" https://eurocommerce-test.cardlink.gr/vpos/shophandlermpi" method="POST" name="test">
<input name="version" type="hidden" value="2" />
<input name="mid" type="hidden" value="0101119349" />
<input name="lang" type="hidden" value="en" />
<input name="deviceCategory" type="hidden" value="0" />
<input name="orderid" type="hidden" value="O170911143656" />
<input name="orderDesc" type="hidden" value="Test order some items" />
<input name="orderAmount" type="hidden" value="0.12" />
<input name="currency" type="hidden" value="EUR" />
<input name="payerEmail" type="hidden" value="cardlink@cardlink.gr" />
<input name="payerPhone" type="hidden" value="30-6900000000" />
<input name="billCountry" type="hidden" value="GR" />
<input name="billZip" type="hidden" value="12345" />
<input name="billCity" type="hidden" value="Athens" />
<input name="billAddress" type="hidden" value="Street 45" />
<input name="confirmUrl" type="hidden" value="https://ecommerce-test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=confirm" />
<input name="cancelUrl" type="hidden" value="https://ecommerce-test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=cancel" />
<input name="digest" type="hidden" value="NCGHNiNtLXY/aMLGSQrogsjlPtPucqQF6NAk1y0+FCg=" />
</form>

1) Concatenate all the values of all the possible fields listed in the table, the same order as parameters are listed in Payment page fields table.

Counter  Post Field    Post field value 
1  version    2 
2  mid    0101119349 
3  lang    en 
4  deviceCategory    0
5  orderid    O170911143656
6  orderDesc    Test order some items 
7  orderAmount    0.12 
8  currency    EUR 
9  payerEmail    cardlink@cardlink.gr 
10  payerPhone    30-6900000000 
11  billCountry   GR
 
13 billZip   12345
14 billCity   Athens
15 billAddress   Street 45
 
     
     
       
34  confirmUrl    https://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo. jsp?cmd=confirm
35  cancelUrl    https://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo. jsp?cmd=cancel

So, the concatenated string of the above values is the following:

20101119349en0O170911143656Test order some items0.12EURcardlink@cardlink.gr30-6900000000GR12345AthensStreet 45https://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=confirmhttps://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=cancel

 

Note: The concatenated string must contain all the values the merchant has sent, not just the required ones (the above string contains the optional values of lang and deviceCategory).

 

2) Add SHARED SECRET

SHARED SECRET is the password between the bank and the merchant and must be added at the end of the previous string. Assume SECRET is «Cardlink1», then the produced sting is the following:

20101119349en0O170911143656Test order some items0.12EURcardlink@cardlink.gr30-6900000000GR12345AthensStreet 45https://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=confirmhttps://ecommerce- test.cardlink.gr/vpostestsv4/shops/shopdemo.jsp?cmd=cancelCardlink1

 

3) Encryption and Encoding using base64 and sha256 functions

The final step of digest calculation is the use of base64 and sha256 functions according to the following rule:

Digest=base64( sha256( utf8bytes(value1|value2|…|secret) ) )

This produces the following result:

NCGHNiNtLXY/aMLGSQrogsjlPtPucqQF6NAk1y0+FCg=

 

if you have trouble calculating the digest, please use the tool.

Digest calculation with XML API 2.1

At VPOS side there are both validations implemented if the Digest values is present then VPOS validates the authentication of message using the digest and merchant shared secret.

Version 2.1 
Base64(SHA256((utf8bytes(canonicalize(Message))+utf8bytes(sharedSecret)))), to be used only if the XML password is not used. The canonicalization method to be used is http://www.w3.org/TR/2001/REC-xml-c14n-20010315

Note that the XML documents should be handled with namespace aware xml libraries (parser/serializer).  When the Message element is serialized and canonicalized it should contain xmlns namespace attribute.

For example a non canonicalized Message element

<Message version=”2.1″ messageId=”M1627047946727″ lang=”en” timeStamp=”2021-07-23T16:45:46.000+03:00″><SaleRequest><Authentication><Mid>0000001</Mid></Authentication><OrderInfo><OrderId>1627047728798</OrderId><OrderDesc></OrderDesc><OrderAmount>1.25</OrderAmount><Currency>EUR</Currency></OrderInfo><PaymentInfo><PayMethod>visa</PayMethod><CardPan>332211223344</CardPan><CardExpDate>2206</CardExpDate><CardCvv2>756</CardCvv2><CardHolderName>John Smith</CardHolderName></PaymentInfo></SaleRequest></Message>

Below is the canonicalized version of Message element (attributes ordered and default xmlns defined):

<Message xmlns=http://www.modirum.com/schemas/vposxmlapi41 xmlns:ns2=http://www.w3.org/2000/09/xmldsig# lang=”en” messageId=”M1627047946727″ timeStamp=”2021-07-23T16:45:46.000+03:00″ version=”2.1″><SaleRequest><Authentication><Mid>0000001</Mid></Authentication><OrderInfo><OrderId>1627047728798</OrderId><OrderDesc></OrderDesc><OrderAmount>1.25</OrderAmount><Currency>EUR</Currency></OrderInfo><PaymentInfo><PayMethod>visa</PayMethod><CardPan>332211223344</CardPan><CardExpDate>2206</CardExpDate><CardCvv2>756</CardCvv2><CardHolderName>John Smith</CardHolderName></PaymentInfo></SaleRequest></Message>

Also take note that in canonicalized form element attributes are ordered lexicographically see https://www.w3.org/TR/2001/REC-xml-c14n-20010315#DocumentOrder

Note for XML API with Three D Secure:

This is 2 step processing at first step merchant should implement MPI plugin session as decribed in Modirum MPI manual and obtain the Three D Secure authentication results from there and then next step is to fill the corresponding values to XML API ThreeDSecure element and proceed with XML api request to VPOS.

XML API plugin example message and digest

Secret=SecRetDigest1

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><VPOS xmlns=http://www.modirum.com/schemas/vposxmlapi41 xmlns:ns2=http://www.w3.org/2000/09/xmldsig#><Message version=”2.1″ messageId=”M1560776758348″ timeStamp=”2019-06-17T16:05:58.348+03:00″><SaleRequest><Authentication><Mid>0000001</Mid></Authentication><OrderInfo><OrderId>1560776271083</OrderId><OrderDesc>Test</OrderDesc><OrderAmount>1.25</OrderAmount><Currency>EUR</Currency><PayerEmail></PayerEmail></OrderInfo><PaymentInfo><PayMethod>visa</PayMethod><CardPan>4016000000002</CardPan><CardExpDate>2206</CardExpDate><CardCvv2>756</CardCvv2><CardHolderName>John Smith</CardHolderName></PaymentInfo></SaleRequest></Message><Digest>xmSXBhrE99FqiP2b73S 0cS+oLrIi8+lng9IS9KmoWpM=</Digest></VPOS>

Message part canonicalized note xmlns added:

<Message xmlns=http://www.modirum.com/schemas/vposxmlapi41 xmlns:ns2=http://www.w3.o rg/2000/09/xmldsig# messageId=”M1560776758348″ timeStamp=”2019-06-17T16:05:58.348+03:00″ version=”2.1″><SaleRequest><Authentication><Mid>0000001</Mid></Authentication><OrderInfo><OrderId>1560776271083</OrderId><OrderDesc>Test</OrderDesc><OrderAmount>1.25</OrderAmount><Currency>EUR</Currency><PayerEmail></PayerEmail></OrderInfo><PaymentInfo><PayMethod>visa</PayMethod><CardPan>4016000000002</CardPan><CardExpDate>2206</CardExpDate><CardCvv2>756</CardCvv2><CardHolderName>John Smith</CardHolderName></PaymentInfo></SaleRequest></Message>SecRetDigest1

Then append SecRetDigest1 and apply sha2-256 function.
You will get digest
<Digest>xmSXBhrE99FqiP2b73S0cS+oLrIi8+lng9IS9KmoWpM=</Digest>

Response example:
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><VPOS xmlns=http://www.modirum.com/schemas/vposxmlapi41 xmlns:ns2=http://www.w3.org/2000/09/xmldsig#><Message version=”2.1″ messageId=”M1560776758348″ timeStamp=”2019-06-17T16:05:58.517+03:00″><SaleResponse><OrderId>1560776271083</OrderId><OrderAmount>1.25</OrderAmount><Currency>EUR</Currency><PaymentTotal>1.25</PaymentTotal><Status>CAPTURED</Status><TxId>927703881</TxId><PaymentRef>104040</PaymentRef><RiskScore>10</RiskScore><Description>OK, CAPTURED response code 00</Description><Attribute  name=”EXTACQUIRERID”>014</Attribute></SaleResponse></Message><Digest>oavTfZECv1L8hKcjw0m V+bOvIjSdq+UNSNU7/xRvnAA=</Digest></VPOS>

Signature calculation with XML API V4.1

Signatures shall be calculated and verified according to documentation https://www.w3.org/TR/xmldsig-core/

Canonicalization method to be used is http://www.w3.org/TR/2001/REC-xml-c14n-20010315

SignatureMethod Algorithm=”http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″

DigestMethod  Algorithm=”http://www.w3.org/2001/04/xmlenc#sha256″

The signed element is Message element referenced with its ID attribute named  messageId.

ID attribute is an attribute which type in schema is defined as xsd:ID.

Messages sent by merchant are signed by merchant private key and verified with merchant certificate.

Messages sent by VPOS service are signed by service provider private key and validated with service provider provided certificate.

XML API plugin example message and signature calculation

Here is an example request message to VPOS and how the signature is calculated.

(used apache santuario)

Merchant Private key PKCS8:

—–BEGIN PRIVATE KEY—–

MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaX7Jd16os2Mti

cXHXGjanQ3fDSwwoRRhVWi12+SiFDMVBpBwZEGdmHopO5cpSGptFxeau7HqGfSaq

5NoI01pbf/OPFpstO4mSlIBj2OO9wzcW2yNeAQjzycEQmgNr1UQACUmXsNzBZZ2m

rcddkdRpxfHPaZx+GIYMdemFY7G0yBXsG0Dq+3hi9kqyGYlAN3PFsqCEdwD3H8qd

5UKz4wKEYhuqhKBZZoGBBUQZt7X9plwdMoZhtqbJIJTpda5Og/yNxkSjiTQrOMnt

vSl5dAQ8dGxoFaKAdvaE09eqt0F6RI76qyUU3B0PKBVB/kIYhvFSvJtef6a8fF4S

y56VOMptAgMBAAECggEBAM9tj1Qsg21OEQNVlzknoTqIj75mDwpBd7e7jOwyCBc5

5jVP2ZDFUDJkWCRRijkrJMrGDTWjU09kmdJCyAkSGgZIJ+aHJqd0ol0lyj8NymZ6

hF2lkpa8jPBleIp4gT9wuMMAD3OTgF4EVBf7giCTYR2H9QV74Da2vL4hUsxtwmNg

2jQjjHTsVA/ESjiyGveh1X6+GV6CsTZsoAWLlOhuDHiOMuOXDBmn9JjArFsl2W4X

yrtrDx68nVdPdIH2LzIrBzqRG6tB9RpNQNWGs/IxuEUG07fLMGzQiureOTUm/ybt

ZrO9Ab59tzWXCFXHljsGJu9SnZuPNOT0L8PuJIxKOIECgYEA9w6hdFaVr0HMnQtX

ndtZQfiqNnQMymV0mR9gtyw20/krOW5yt7WqhrzzTB72m4bsm27Yz3Dn0jfhQ1h5

zyihrT+FGeF6jS6+Hr3FXFyMizxH9AZPl13UmZo1fKxeoL+sE5PppFE9Qlsz0TBp

2phlVjzLI7i3KOu8Hyzt/rafZDkCgYEA4kdFMSHTQGLounpPauKaVi8v9TjyFdST

qSuQ0pMG4R9xuZ0x52L081goYmxo4jDo7P+m3iHDFdJqg+D7aAVay4Hv0PGKIq8G

vOAXm6mnXBaIMDVMnTRtqRynDoo2qKp9UU2Sv4D0L6Zbm9axDxMvqXCa8Lz5Kbnh

zJufUAwzn9UCgYEAkboGkDn2Zv8X81ZaYxmcZ6aGuEHxvXzkruFsSf+Bg71IusKk

ViqJIJrZo//rlMecTv6uUoYVp9EgRXott30PCMMb/q0afaahrD5h6N4KZKK1CoKi

dfV5zvTAMf72fjkxBgdMXIky6i4jvXOiLLeRprGLXVG6cB/EwlrdM06DbDkCgYBc

TdJt3mx8gVyKZUZsRY/LxGf90oL+YL7zbXAgVhWiU99iZjtrNjTR545hx/NpAaai

tw7s4jzgc/s7XNVxc228Qn7/buh4iYloFsnKmARLTm2zrKpaHn71U1jaV4tAdnu0

ZL6OHB6AKY6JHaUQjzUMG4E43v2NBeSUQI9WagPNGQKBgDj5qk4Jauy8zg/IBkXD

eJsgwGrMH7o1vj2Uhcd2K2NrxO3qRaJitNXH+cso836/Ez///kdepX3hQ3gKZS7i

aGhDFF3r0LU2OmskhoDSyhzVlCgsXbW1skFwL3Y161uYHwgpkFqrAODONXLu3PBd

S8jJbKkA3lQnmCCbET3NLfIV

—–END PRIVATE KEY—–

Merchant certificate X509:

—–BEGIN CERTIFICATE—–

MIIDuzCCAqOgAwIBAgIJANh5ptk5BWu5MA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV

BAYTAkVFMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHbXkgQ2l0eTEVMBMG

A1UECgwMQ29tcGFueSBOYW1lMRAwDgYDVQQLDAc3NzExMjIzMRcwFQYDVQQDDA53

d3cubXlzaXRlLmNvbTAeFw0xNzAzMjkxNzM3MDFaFw0yMTAzMjgxNzM3MDFaMHQx

CzAJBgNVBAYTAkVFMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHbXkgQ2l0

eTEVMBMGA1UECgwMQ29tcGFueSBOYW1lMRAwDgYDVQQLDAc3NzExMjIzMRcwFQYD

VQQDDA53d3cubXlzaXRlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC

ggEBANpfsl3XqizYy2JxcdcaNqdDd8NLDChFGFVaLXb5KIUMxUGkHBkQZ2Yeik7l

ylIam0XF5q7seoZ9Jqrk2gjTWlt/848Wmy07iZKUgGPY473DNxbbI14BCPPJwRCa

A2vVRAAJSZew3MFlnaatx12R1GnF8c9pnH4Yhgx16YVjsbTIFewbQOr7eGL2SrIZ

iUA3c8WyoIR3APcfyp3lQrPjAoRiG6qEoFlmgYEFRBm3tf2mXB0yhmG2pskglOl1

rk6D/I3GRKOJNCs4ye29KXl0BDx0bGgVooB29oTT16q3QXpEjvqrJRTcHQ8oFUH+

QhiG8VK8m15/prx8XhLLnpU4ym0CAwEAAaNQME4wHQYDVR0OBBYEFJaXNDk3UIJT

7bjuedk13vmz62RjMB8GA1UdIwQYMBaAFJaXNDk3UIJT7bjuedk13vmz62RjMAwG

A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJx7UBdBddBbJ8sz/Fa3YvDl

VR/GNTLp/haKC6G+FA97H5u2S7OGgXUnIX2T3M94QllhTykkzfr1zJeDZD+YrYyh

Ayp/ykHL0gk0tumHw8DN1BRmglRMc4QEXXHsx1HnMlcS0uE622M2+IQeDzDtLYpf

XL36Dqoik0hIuNSjlxqlIX4kBweA83Xx9IGyhsMhXHSS0BcPVmup97PTAs81YGOu

7vVgzyLBTHjabRktd0hVdm9+EJ/RMMFTW4XM+Ue2ekFx3uEX2B53ND6Mx5mtP/pi

bQ7/860FXUNdrHbcQCFufqhk7Ikr3+kv+Rqmh5DmrUbblpmXFvm6iLc6uYZqIvE=

—–END CERTIFICATE—–

Service provider certificate:

—–BEGIN CERTIFICATE—–

MIID5TCCAo0CBFjeXq8wDQYJKoZIhvcNAQELBQAwdzEoMCYGA1UEAxMfVlBPUyBERU1PIHZwb3Nh

ZG1pbi5tb2RpcnVtLmNvbTENMAsGA1UECxMEVlBPUzEQMA4GA1UEChMHTW9kaXJ1bTEQMA4GA1UE

BxMHVGFsbGlubjELMAkGA1UECBMCSE0xCzAJBgNVBAYTAkVFMB4XDTE3MDMzMTEzNTAzOVoXDTIy

MDkyMTEzNTAzOVowdzEoMCYGA1UEAxMfVlBPUyBERU1PIHZwb3NhZG1pbi5tb2RpcnVtLmNvbTEN

MAsGA1UECxMEVlBPUzEQMA4GA1UEChMHTW9kaXJ1bTEQMA4GA1UEBxMHVGFsbGlubjELMAkGA1UE

CBMCSE0xCzAJBgNVBAYTAkVFMIIBYjANBgkqhkiG9w0BAQEFAAOCAU8AMIIBSgKCAUEAyhFCdFGD

pchDXC7ryDUiMOlRHjce4N9e4hNUZ6+hTshRBTNeHqcTfhxKuiReaC6AVbQEbBYBGCUs8EQAWppK

RIB+ZnTytY8bhJqQ1YuiWvAN5cTBLoS2jE5vxf/Xx/+G+UhjfmK6XM0UKnQ4mR+MKM5/iSgV/Un7

ysHoLLepwefEUBQEODqAIsc6N5pMeeShT/66WEtxEkiXQPn48PXDRLLzSBzB247w03r+92WWrlVe

IMgTQc0kgx2gsgMziiqiUDSB69Bm/ugT81wDcUNklmbo8r3IsxtjOT+/HQ8Qbo4vQpJI7yzIcnvt

6U8Ub5TLjz4UmIBg8y6lY/kbJoxA/4n/M+1MwZqgM7cKGi5lG429A3h/1g2zhQ8bZBexnY5FLW1G

PTCS4ahE67ZYl8CWXjoDAzFtVcdpMDFnvZ6noMkCAwEAATANBgkqhkiG9w0BAQsFAAOCAUEAp0mN

/2Ml6tVC8Zi0bkXJ8j+bUxaxCUU1nV7htzWOqlAsQn1mVb7lbkLZgOc7RfD5CxdLspAVIVU1Gekp

/tSLjbdA3obSlBFmIm5yU4PGN9YjLRi5jbAAJNhJYThFB0YJu4M6tqX0nbxX6GphPeh2ruQ6WzeS

KwUf62gqd96WZeIwAKLoAZng4G9LZNITL7jUgl4OWq9OzZ+JYpe/rSz1tKWAg9r5U/AEkoZasfPo

3MLQlNCTh/WQm8jmtsyglct4k5SNI3ABhFcPfcR0PIhCjTVd7vlY8NcdaxSYYRzQgKZ7N8pdhvi3

NyPZmbu4OJXkc4Fupuyp2YxhGh0AtLKvdPRmybNZCmTRejgGbJeE6LjkcJ2zcunb+LxbyoxJ1DdU

K1tddzVPdH+QK8q3EKBNt0H3KwbRPk9qRmH4xuoX4XA=

—–END CERTIFICATE—–

Example code:

import javax.xml.transform.Transformer;

import javax.xml.transform.TransformerFactory;

import javax.xml.transform.dom.DOMSource;

import javax.xml.transform.stream.StreamResult;

import javax.xml.transform.stream.StreamSource;

import org.apache.xml.security.keys.KeyInfo;

import org.apache.xml.security.keys.content.X509Data;

import org.apache.xml.security.keys.content.x509.XMLX509Certificate;

import org.apache.xml.security.signature.XMLSignature;

public class Signer

{

public byte[] sign(VPOS root, PrivateKey prik, java.security.cert.X509Certificate[] crts) throws Exception

{

org.w3c.dom.Document dom = apis.marschalToDOM(root);

// apis.normalizeDOM(dom); dom nomralization is very slow using instead

// msg.setIdAttribute(“messageId”, true);

Element vpos = dom.getDocumentElement();

XMLSignature xmlsigAp = new XMLSignature(dom, null,

“http://www.w3.org/2001/04/xmldsig-more#rsa-sha256”,

“http://www.w3.org/TR/2001/REC-xml-c14n-20010315”);

Element sigel = xmlsigAp.getElement();

vpos.appendChild(sigel);

Element msg = (Element)vpos.getFirstChild();

// setting id attribute instead of dom normalization

msg.setIdAttribute(“messageId”, true);

xmlsigAp.addDocument(“#” + msg.getAttribute(“messageId”), null,

“http://www.w3.org/2001/04/xmlenc#sha256”, null, null);

for (int i = 0; crts != null && i < crts.length; i++)

{

xmlsigAp.addKeyInfo(crts[i]);

}

xmlsigAp.sign(prik);

ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);

TransformerFactory transfac = TransformerFactory.newInstance();

Transformer trans = transfac.newTransformer();

trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, “no”);

trans.setOutputProperty(OutputKeys.INDENT, “no”);

trans.setOutputProperty(OutputKeys.ENCODING, “utf-8”);

DOMSource source = new DOMSource(dom);

trans.transform(source, new StreamResult(bos));

return bos.toByteArray();

}

}

 

Example sale request (assume there is no line breaks until end of <Message> part)

<VPOS xmlns=”http://www.modirum.com/schemas/vposxmlapi41″
xmlns:ns2=”http://www.w3.org/2000/09/xmldsig#”><Message messageId=”M1560776270228″
timeStamp=”2019-06-17T15:57:50.228+03:00″
version=”4.1″><SaleRequest><Authentication><Mid>0000001</Mid></Authentication><OrderInfo><Ord
erId>1560776235400</OrderId><OrderDesc>Test</OrderDesc><OrderAmount>1.25</OrderAmount><Cu
rrency>EUR</Currency><PayerEmail/></OrderInfo><PaymentInfo><PayMethod>visa</PayMethod><Car
dPan>4016000000002</CardPan><CardExpDate>2206</CardExpDate><CardCvv2>756</Card
Cvv2><CardHolderName>John
Smith</CardHolderName></PaymentInfo></SaleRequest></Message><ds:Signature xmlns:ds=”http://
www.w3.org/2000/09/xmldsig#”><ds:SignedInfo> <ds:CanonicalizationMethod
Algorithm=”http://www.w3.org/TR/2001/REC-xml-c14n-20010315″/><ds:SignatureMethod
Algorithm=”http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″/> <ds:Reference
URI=”#M1560776270228″><ds:DigestMethod Algorithm=”http://www.w3.org/2001/04/xmlenc#sha256″/>
<ds:DigestValue>82t/HCbRKUrAKVsA1tOpU8zXi3wIupTUeBndZ90VALM=</ds:DigestValue></ds:Ref
erence></ds:SignedInfo><ds:SignatureValue>
DhADR21OEzIikjwgZh61pibBULtI0iRbkSEt6z2mdVGpQRgI3UFIepkYvTeNZv84cF2jM6JCrFbxdXMIR
Q643rFXwOAnstv0QyRFPD4XCQDltSfoqDNfjAQE2wXmYWgHGJdI/0Vu12TJ64XzdEhb4E6t8yGfyYL
6DdXZk4oBRZxBRqGBA6zxyDRdRvLq9V+LGIwZk4J7p6M+wZWDTb50/pOSU2wlP/s4IPtQvZQYWct
9Huq/sFI+qwAG7na0L25zE9cB467lcaKmgGGLXFrRwDX6xAmoZOwFIW5x0CXbtM2X2j8vH53/Hfh1r
dsWRxbOs7+ObLYvct/BA6KRbMxBPA==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509C
ertificate>MIIDuzCCAqOgAwIBAgIJANh5ptk5BWu5MA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNVB
AYTAkVFMREwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHbXkgQ2l0eTEVMBMGA1UE
CgwMQ29tcGFueSBOYW1lMRAwDgYDVQQLDAc3NzExMjIzMRcwFQYDVQQDDA53d3cubXlzaXR
lLmNvbTAeFw0xNzAzMjkxNzM3MDFaFw0yMTAzMjgxNzM3MDFaMHQxCzAJBgNVBAYTAkVFM
REwDwYDVQQIDAhNeSBTdGF0ZTEQMA4GA1UEBwwHbXkgQ2l0eTEVMBMGA1UECgwMQ29tc
GFueSBOYW1lMRAwDgYDVQQLDAc3NzExMjIzMRcwFQYDVQQDDA53d3cubXlzaXRlLmNvbTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANpfsl3XqizYy2JxcdcaNqdDd8NLDChFGF
VaLXb5KIUMxUGkHBkQZ2Yeik7lylIam0XF5q7seoZ9Jqrk2gjTWlt/848Wmy07iZKUgGPY473DNxbbI1
4BCPPJwRCaA2vVRAAJSZew3MFlnaatx12R1GnF8c9pnH4Yhgx16YVjsbTIFewbQOr7eGL2SrIZiUA3c
8WyoIR3APcfyp3lQrPjAoRiG6qEoFlmgYEFRBm3tf2mXB0yhmG2pskglOl1rk6D/I3GRKOJNCs4ye29K
Xl0BDx0bGgVooB29oTT16q3QXpEjvqrJRTcHQ8oFUH+QhiG8VK8m15/prx8XhLLnpU4ym0CAwEAA
aNQME4wHQYDVR0OBBYEFJaXNDk3UIJT7bjuedk13vmz62RjMB8GA1UdIwQYMBaAFJaXNDk3UI
JT7bjuedk13vmz62RjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJx7UBdBddB
bJ8sz/Fa3YvDlVR/GNTLp/haKC6G+FA97H5u2S7OGgXUnIX2T3M94QllhTykkzfr1zJeDZD+YrYyhAyp
/ykHL0gk0tumHw8DN1BRmglRMc4QEXXHsx1HnMlcS0uE622M2+IQeDzDtLYpfXL36Dqoik0hIuNSjl
xqlIX4kBweA83Xx9IGyhsMhXHSS0BcPVmup97PTAs81YGOu7vVgzyLBTHjabRktd0hVdm9+EJ/RMM
FTW4XM+Ue2ekFx3uEX2B53ND6Mx5mtP/pibQ7/860FXUNdrHbcQCFufqhk7Ikr3+kv+Rqmh5DmrUbb
lpmXFvm6iLc6uYZqIvE=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature></VPOS>

Response signed by service provider (assume no line breaks until end of <Message> part)

<VPOS xmlns=”http://www.modirum.com/schemas/vposxmlapi41″
xmlns:ns2=”http://www.w3.org/2000/09/xmldsig#”><Message messageId=”M1560776270228″
timeStamp=”2019-06-17T15:57:50.502+03:00″ version=”4.1″><SaleResponse><OrderId>1560776235400</OrderId><OrderAmount>1.25</OrderAmount
><Currency>EUR</Currency><PaymentTotal>1.25</PaymentTotal><Status>CAPTURED</Status><TxId
>927703821</TxId><PaymentRef>104037</PaymentRef><RiskScore>10</RiskScore><Description>OK,
CAPTURED response code 00</Description><Attribute
name=”EXTACQUIRERID”>014</Attribute></SaleResponse></Message><ds:Signature xmlns:ds=”http://
www.w3.org/2000/09/xmldsig#”> <ds:SignedInfo><ds:CanonicalizationMethod
Algorithm=”http://www.w3.org/TR/2001/REC-xml-c14n-20010315″/> <ds:SignatureMethod
Algorithm=”http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″/><ds:Reference
URI=”#M1560776270228″>
<ds:DigestMethodAlgorithm=”http://www.w3.org/2001/04/xmlenc#sha256″/><ds:DigestValue>6nt7AHK5
fyrhVW/Mdp9Slx/NBHMfekjbfThFVBRKkt8=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:Si
gnatureValue>Wjb1yBQzPok9VKu9U37ua3i/OsqcMZQKAvyE6iOML43rteMgorpmwlOWQSQvLHqFQt
s4HVxvMkruDufn7wuRfqmjDWLzgUqHpFTz+heOGDXhc88ovCaE7vFeYDJg+/isHjaO29ETe6+NH8oD
vq4/no00mA/eHWqNB+vH51+jQCZfRI+tavz1iPAFLAF9Sl5IitaiuGXkEOoOxMbZ7FAb8GT++1MuZYD
FgWLhZ/skR57b/LobPY5n5+AkEdqc86Dyk8/zOJC6RRS9TuJWoAIgJOaVNulSB6X/lsmfu7+GDDEynqx
obZ0djEMwXhfLSfNlNHHqkePKxEhlXMFkEL5B1jGTnHs26yymy9JYq6TtwUq9XjEn2XnYl0Oa9hwCF
IJ8a5p8u0nPJqtWNJKqDD1YH7FSEc7cBbM8SoTjXAyLZssZmBvJ+bba+FyIl5wTeD2RKtPenptu3uoyyL
60c+ZeGs9+N3sfWh2jpztcSAj4xLQEre59UvFE478Kw78MfF0k</ds:SignatureValue><ds:KeyInfo><ds:X
509Data><ds:X509Certificate>MIIEXjCCAsYCAQEwDQYJKoZIhvcNAQELBQAwdTElMCMGA1UEA
xMcQ2FyZGxpbmsgVUFUIFNpZ25pbmcgYW5kIENTRTENMAsGA1UECxMERUNPTTERMA8GA1U
EChMIQ2FyZGxpbmsxDzANBgNVBAcTBkF0aGVuczEMMAoGA1UECBMDQVRIMQswCQYDVQQ
GEwJHUjAeFw0xODA2MjEyMTAwMDBaFw0yNTA2MjIyMDU5NTlaMHUxJTAjBgNVBAMTHENhc
mRsaW5rIFVBVCBTaWduaW5nIGFuZCBDU0UxDTALBgNVBAsTBEVDT00xETAPBgNVBAoTCEN
hcmRsaW5rMQ8wDQYDVQQHEwZBdGhlbnMxDDAKBgNVBAgTA0FUSDELMAkGA1UEBhMCR1I
wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDlZIj4eMY2hU7ot4kkgB1e7xJniAe07ntR
VwPZdJ1cxevLvSoQMvgd8070RrT7cPDXp6iJIl0RKBnCwZspwoO5evUngdfoAleyLSVUXljKp2G/e6Kt2
2RMCLtYsqNv4qFW5nW8XwB88wvqziSMPu9Mo1gGhOxWpS4Viy3NvrtEVOWXvssx+ZLPolb3AW93
w7BOfzEpt7LM3GwrSYZuPoPHcwdkBs0nF+htIEOq/2T7GDcZPNIUmllu4nQt6u7T1SJ0/TpdHta/p55xpt
E7QLZlNdphIxvu4Zc9U7mwvlCN8MqMNQnQSFlqnBdOgtQ5gxfE8x/cSWOVLzTh6dWOc2o7aiAhk8sV
opl7N4jeL4U4Nvp0GyDodoWgUJeweDookIb9DL2fgQeBLKn8ZFDPOyoBQSNr8AAm3p0bgTDY4XkT
uav919LGgCjR5k389CW256zXCgsj5Dnn8gcTrf0mwziUbjlGt/UIy7CA7kmpELwna4NNo7Lt6laILqletJi1r
lECAwEAATANBgkqhkiG9w0BAQsFAAOCAYEAVkOFbVwxj/pbnTH8Z2y/17P1yzv4H6vKB2RdG60
CMSou0X/WNybBgaMSf6qJJs3osUC68qx27Q3pYp4i7onsTlNedhSsUVZVabRHXkjLxGLx9saZNiZ9turI
yxzfC7VdeGaogvmcFPZAFgkGSFy4tAZz8fIkL7XI9pp5NTrjP9AL1ETVgwoHFKoeEKU1ewgQGRXpsM
2sQnanMrTOgfVWz+qmaMmCcgeuQnYDPkZXX3jo456N0IDcGhJRmzkO8x0ge3DGyTc2mdS+38c61V
EDd2TQHDHJuGsjCSVMjYh83JF7Ut3imFYhv3jgmHNkEDsp7XU81UMaV1nD0WzwNTbuMlyuvUQlt
LtQ0lciDl+yT7zciHZr3JkL3am9lCtny/DROyw7pZnDCbWHaUKl4pV5UtwCIT/o5v7yo3av1z5o6Ufial+ke
meyhcU7PtMXZ6mgW9Hcq4htX1BTl/LsTN/42XxvrdzystkmvJeSlrNLPbeASi8MC3j/xQdUjc6mWQ/t</d
s:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature></VPOS>

Signature calculation sample codes
Java
.NET
PHP
java.security.PrivateKey privateKey = getPrivateKey(); //fetch your private key
java.security.Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(concatenatedValues.toString().getBytes(StandardCharsets.UTF_8));
byte[] sigBytes=signature.sign();
String sigStr=Base64.encode(sigBytes);
public static string sign(string valueToSign, String privateKey)
{
byte[] keybytes= parseKey(privateKey);
byte[] toSign = System.Text.Encoding.UTF8.GetBytes(valueToSign);
RSACryptoServiceProvider RSAalg = DecodePrivateKeyInfo(keybytes);
byte[] signature=RSAalg.SignData(toSign, "SHA256"); //RSAwithSHA256
string sigStr= Convert.ToBase64String(signature);
return sigStr;
}
value_to_sign   = $value_to_sign;
    $this->private_key     = $this->set_private_key( $private_key );
    $this->signature_value = $this->sign();
    }

    private function sign() {
        openssl_sign( $this->value_to_sign, $signature, $this->private_key, OPENSSL_ALGO_SHA256 );

        return base64 _ encode( $signature ); // Please remove spaces in base64 function
    }

    private function set_private_key( $key ) {
        if ( ! $this->starts_with( $key, '-----BEGIN PRIVATE KEY-----' ) ) {
            return "-----BEGIN PRIVATE KEY-----\n" . $key . "\n-----END PRIVATE KEY-----";
        }

        return $key;
    }

    private function starts_with( $string, $startString ) {
        $len = strlen( $startString );

        return ( substr( $string, 0, $len ) === $startString );
    }
}

$private_key   = ''; // add your private key here
$value_to_sign = ''; // add the canonicalized message here
$sign          = new Signature( $value_to_sign, $private_key );
echo $sign;

Still looking for help?

Send us e-mail

We’re here to help. Get in touch and we’ll get back to you as soon as we can.