Signature generation and verification

Overview

All the communication between merchant and the ECommPay payment platform is protected by using the TLS protocol version 1.2 or higher. This ensures message confidentiality while in transit, though the protocol cannot guarantee message integrity and ensure that the message author possesses the secret key. Therefore, every message must be digitally signed by using the secret key issued by ECommPay for the merchant and known only to the merchant and the ECommPay payment platform.

You must create and add a digital signature to every message you send to the ECommPay payment platform and verify signature of every message you receive from the payment platform, either synchronous or asynchronous. You can implement digital signature generation either from scratch or by using the SDK available from ECommPay. (For more information about the SDK, see SDK.).

There are many reasons why message integrity can be compromised, but in any case compromised messages data can never be considered as valid.

This section describes the algorithms for generation of digital signatures for outgoing messages and for integrity verification of incoming messages; also, this section includes examples that use these algorithms and forms that allow you to test signature generation and verification.

Signature generation

Signing algorithm

The algorithm input includes the following:

  1. Data to sign.

    Generally, this is request body in JSON format without the signature parameter.

  2. Signing key (“salt”).
    Note: When using the Data API, you need to use the keys and tokaens obtained through the Dashboard (Dashboard Light) interface. (For details, see API Tokens.)

    For debugging and testing purposes, you are free to use any signing key, though for signing requests in production environment, you are required to use your production secret key.

Depending on the algorithm implementation, its output may be either signature or signed data. Generally, the algorithm output consists of request body in JSON format with integrated signature parameter.

The algorithm description, the example, and test form below include the most common algorithm implementation that includes request body in JSON format both as input (without the signature parameter) and output (with the signature parameter).

Thus, the algorithm includes the following steps:

  1. Input validation Make sure the following requirements are met:

    1. Data conforms to the JSON format.
    2. Data to sign does not contain any signature parameter even if it is empty.
    3. The signing key (“salt”) is readily available.
  2. Conversion of all the strings to UTF-8 with alphabetical sorting. Complete the following steps:

    1. Encode any Boolean values as follows: replace false with 0, replace true with 1.

      This rule applies only to Boolean values! If any string parameter contains "false" or "true" string value, the value is not replaced with 0 or 1 but is treated as any other string value.

    2. Convert each parameter into a string that contains the full path to the parameter (with all its parents), parameter name, and parameter value:

      <parent_1>:...:<parent_n>:<parameter_name>:<parameter_value>

      where parents are the object(s) and/or arrays in which the parameter is contained. Parents are ordered by embedding level starting with the topmost one. The parent names, parameter name, and parameter value are delimited by colon (:); delete any commas between “key-value” pairs and any quotation marks that delimit string values.

    3. Leave any empty parameter values empty. In other words, do not replace any empty values with blank space or null. For instance, "payment_description":"" is replaced with payment_description:.
    4. Convert all the strings to UTF-8.
    5. Sort the strings in alphabetical order and join them in a single string by using semicolon (;) as a delimiter.
  3. Calculation of HMAC code by using the key and the SHA-512 hash function. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key. The HMAC code must be calculated as a raw binary data.
  4. Encoding the HMAC code by using the Base64 scheme. Encoding the HMAC code by using the Base64 scheme to obtain the signature for the initial data.
  5. Adding signature. Add the signature parameter to the request body using the signature from the previous step as its value.

Example of data request through Dashboard

Suppose that you need to generate a signature for a Dashboard request in the following scenario:

  • Signing key : secret.
  • Preliminary request body version where the value for the signature is missing:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Europe/Moscow",
     "signature": "<digital signature to generate>"
    }

The task is to generate the signature; in other words, you need to compute the value for the signature parameter and add it in the request. Complete the following steps:

  1. Make sure there is no signature parameter in your request even it is empty:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Europe/Moscow",
     "signature": "<digital signature to generate>"
    }
  2. Convert all the strings to UTF-8 as per algorithm description:
    token:WKiarERJ5pcceNerpM9R5TNnyPTQMl
    interval:from:2020-01-01 14:53:55
    interval:to:2020-01-30 13:53:59
    project_id:0:183
    limit:3
    offset:0
    tz:Europe/Moscow
  3. Sort the strings in alphabetical order:
    interval:from:2020-01-01 14:53:55
    interval:to:2020-01-30 13:53:59
    limit:3
    offset:0
    project_id:0:183
    token:WKiarERJ5pcceNerpM9R5TNnyPTQMl
    tz:Europe/Moscow
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    interval:from:2020-01-01 14:53:55;interval:to:2020-01-30 13:53:59;limit:3;offset:0;project_id:0:183;token:WKiarERJ5pcceNerpM9R5TNnyPTQMl;tz:Europe/Moscow
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    w6ZW/DPURM2LXYcviD5yDlwe/gV+yBhCZaL0XbfHkoefY3OuIccdDAyECbhl7/GqA8dZ+R6XFwBUzzm94ywjrw==
  6. Add the resulting signature in the request body:
    {
      "token": "WKiarERJ5pcceNerpM9R5TNnyPTQMl",
      "interval": {
        "from": "2020-01-01 14:53:55",
        "to": "2020-01-30 13:53:59"
      },
      "project_id": [
        183
      ],
      "limit": 3,
      "offset": 0,
      "tz": "Europe/Moscow",
     "signature": "w6ZW/DPURM2LXYcviD5yDlwe/gV+yBhCZaL0XbfHkoefY3OuIccdDAyECbhl7/GqA8dZ+R6XFwBUzzm94ywjrw=="
    }

Request signature generation form

Signature verification

Verification algorithm

The algorithm input includes the following:

  1. Signed data to verify.

    Generally, this is a response body in JSON format with the signature parameter.

  2. Verification key (“salt”). It must be the same key that was previously used for signing the data to verify.

Depending on the algorithm implementation, its output may be either a generated signature or the information whether the generated signature matches the one included in the response.

The algorithm description, the example, and test form below use the most common algorithm implementation that includes response body in JSON format as input (without the signature parameter) and output (with the signature parameter) which is the result of signature verification.

Thus, the algorithm includes the following steps:

  1. Input validation Make sure the following requirements are met:

    1. Data conforms to the JSON format.
    2. Data to sign contains a signature parameter with the signature value.
    3. The signing key (“salt”) is readily available.
  2. Signature retrieval from the data to verify. Store the value of the signature parameter value for further reference and remove the parameter from the input data.
  3. Generating the signature for input data:
    1. Conversion of all the strings to UTF-8 with alphabetical sorting. Complete the following steps:
      1. Encode any Boolean values as follows: replace false with 0, replace true with 1.

        This rule applies only to Boolean values! If any string parameter contains "false" or "true" string value, the value is not replaced with 0 or 1 but is treated as any other string value.

      2. Convert each parameter into a string that contains the full path to the parameter (with all its parents), parameter name, and parameter value:

        <parent_1>:...:<parent_n>:<parameter_name>:<parameter_value>

        where parents are the object(s) and/or arrays in which the parameter is contained. Parents are ordered by embedding level starting with the topmost one. The parent names, parameter name, and parameter value are delimited by colon (:); delete any commas between “key-value” pairs and any quotation marks that delimit string values.

      3. Leave any empty parameter values empty. In other words, do not replace any empty values with blank space or null. For instance, "payment_description":"" is replaced with payment_description:.
      4. Add index numbers to array elements starting with zero, for instance ["alpha", "beta", "gamma"] is replaced with three strings: 0:alpha, 1:beta, and 2:gamma.
      5. Empty arrays are totally ignored and not included in the string set used to generate the signature.
      6. Convert all the strings to UTF-8.
      7. Sort the strings in alphabetical order and join them in a single string by using semicolon (;) as a delimiter.
    2. Calculation of HMAC code by using the key and the SHA-512 hash function. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key. The HMAC code must be calculated as a raw binary data.
    3. Encoding the HMAC code by using the Base64 scheme. Encoding the HMAC code by using the Base64 scheme to obtain the signature for the initial data.
  4. Signature matching Compare the generated signature with the signature stored in step 2. If the signatures match, the data are authentic and its integrity is considered confirmed; otherwise, the data is considered compromised and cannot be used for production purposes.

Example of verifying response with operations

Suppose that you need to verify the signature a callback in the following scenario:

  • Signing key : secret.
  • The response body contains the following information:

    Figure: Response body

    {
      "operations": [
        {
          "project_id": "183",
          "operation_id": "9048253065548",
          "payment_id": "EP834a-40521580376090593",
          "operation_type": "cancel",
          "operation_status": "success",
          "account_number": "424242******4242",
          "customer_ip": "185.123.193.224",
          "payment_method_name": "visa",
          "payment_method_type": "visa",
          "payment_description": null,
          "operation_created_at": "2020-01-30T12:29:03+03:00",
          "operation_completed_at": "2020-01-30T12:29:04+03:00",
          "provider_date": null,
          "shipment_date": "",
          "mid": "3416123",
          "sum_initial": {
            "amount": 2000,
            "currency": "RUB"
          },
          "sum_converted": {
            "amount": 2000,
            "currency": "RUB"
          },
          "provider_name": "Dashboard Provider Card",
          "fee_currency": null,
          "fee_amount": 0,
          "arn": null,
          "rrn": null
        }
      ],
      "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="
    }

The signature is verified as follows:

  1. Remove the signature parameter and its value from the callback:
    {
      "operations": [
        {
          "project_id": "183",
          "operation_id": "9048253065548",
          "payment_id": "EP834a-40521580376090593",
          "operation_type": "cancel",
          "operation_status": "success",
          "account_number": "424242******4242",
          "customer_ip": "185.123.193.224",
          "payment_method_name": "visa",
          "payment_method_type": "visa",
          "payment_description": null,
          "operation_created_at": "2020-01-30T12:29:03+03:00",
          "operation_completed_at": "2020-01-30T12:29:04+03:00",
          "provider_date": null,
          "shipment_date": "",
          "mid": "3416123",
          "sum_initial": {
            "amount": 2000,
            "currency": "RUB"
          },
          "sum_converted": {
            "amount": 2000,
            "currency": "RUB"
          },
          "provider_name": "Dashboard Provider Card",
          "fee_currency": null,
          "fee_amount": 0,
          "arn": null,
          "rrn": null
        }
      ],
      "signature": "EksxDdDygDQ30JKsfK6QSvubpNRSj3wtLI5FzWDJuNY0nEhLXt65Y77dtKMJRcd39NegA7YK1eojA2EB1hIbnQ=="
    }
  2. Convert all the parameter string to UTF-8 according to the algorithm description:
    operations:0:project_id:183
    operations:0:operation_id:9048253065548
    operations:0:payment_id:EP834a-40521580376090593
    operations:0:operation_type:cancel
    operations:0:operation_status:success
    operations:0:account_number:424242******4242
    operations:0:customer_ip:185.123.193.224
    operations:0:payment_method_name:visa
    operations:0:payment_method_type:visa
    operations:0:payment_description:
    operations:0:operation_created_at:2020-01-30T12:29:03+03:00
    operations:0:operation_completed_at:2020-01-30T12:29:04+03:00
    operations:0:provider_date:
    operations:0:shipment_date:
    operations:0:mid:3416123
    operations:0:sum_initial:amount:2000
    operations:0:sum_initial:currency:RUB
    operations:0:sum_converted:currency:RUB
    operations:0:sum_converted:amount:2000
    operations:0:provider_name:Dashboard Provider Card
    operations:0:fee_currency:
    operations:0:fee_amount:0
    operations:0:arn:
    operations:0:rrn:
  3. Sort the strings in alphabetical order:
    operations:0:account_number:424242******4242
    operations:0:arn:
    operations:0:customer_ip:185.123.193.224
    operations:0:fee_amount:0
    operations:0:fee_currency:
    operations:0:mid:3416123
    operations:0:operation_completed_at:2020-01-30T12:29:04+03:00
    operations:0:operation_created_at:2020-01-30T12:29:03+03:00
    operations:0:operation_id:9048253065548
    operations:0:operation_status:success
    operations:0:operation_type:cancel
    operations:0:payment_description:
    operations:0:payment_id:EP834a-40521580376090593
    operations:0:payment_method_name:visa
    operations:0:payment_method_type:visa
    operations:0:project_id:183
    operations:0:provider_date:
    operations:0:provider_name:Dashboard Provider Card
    operations:0:rrn:
    operations:0:shipment_date:
    operations:0:sum_converted:amount:2000
    operations:0:sum_converted:currency:RUB
    operations:0:sum_initial:amount:2000
    operations:0:sum_initial:currency:RUB
    
  4. Join all the strings in a single string by using semicolon (;) as a delimiter:
    operations:0:account_number:424242******4242;operations:0:arn:;operations:0:customer_ip:185.123.193.224;operations:0:fee_amount:0;operations:0:fee_currency:;operations:0:mid:3416123;operations:0:operation_completed_at:2020-01-30T12:29:04+03:00;operations:0:operation_created_at:2020-01-30T12:29:03+03:00;operations:0:operation_id:9048253065548;operations:0:operation_status:success;operations:0:operation_type:cancel;operations:0:payment_description:;operations:0:payment_id:EP834a-40521580376090593;operations:0:payment_method_name:visa;operations:0:payment_method_type:visa;operations:0:project_id:183;operations:0:provider_date:;operations:0:provider_name:Dashboard Provider Card;operations:0:rrn:;operations:0:shipment_date:;operations:0:sum_converted:amount:2000;operations:0:sum_converted:currency:RUB;operations:0:sum_initial:amount:2000;operations:0:sum_initial:currency:RUB
  5. Calculate the HMAC code for the string by using the SHA-512 hash function and secret key, and then encode the HMAC code by using the Base64 scheme:
    TiDoAPZSQR4Clhg5qj2wLD2tTatx0AUa0erwV++fkOV4kfxy/bBuE5hsnvyk2dzADS3tFC20+czK1dK6YCaJ3g==
  6. Compare the generated signature and the one included in the callback.

    In our case, the signature differ which means that the callback is invalid and must be ignored.

Signature verification form