Проверить sha256 в ответе платежной системы UnitPay (PHP)

ребята. Мучаюсь уже два дня. Никак не могу правильно сформировать sha256

Цифровая подпись. Образуется как sha256(method + "{up}" + params + "{up}" + secretKey),

где sha256 - метод шифрования;

"{up}" - разделитель параметров в хеш-функции;

method - тип вызова (check, pay, error); params - значения параметров из массива params, объединенные разделителем "{up}".

Все параметры должны быть предварительно отсортированы по ключу, в склейке не участвуют параметры sign и signature;

secretKey - секретный ключ проекта (доступен в личном кабинете);

Пример расчета подписи для запроса http://partnerUrl?method=check & params=bob & params[c]=sam & params[a]=tod и секретного ключа "a1b1c1d1" sha256("check{up}tod{up}bob{up}sam{up}a1b1c1d1")

Ответ UnitPay

array (
)
array (
  'action' => 'unitpay',
  'method' => 'pay',
  'params' =>
  array (
    'account' => 'test',
    'date' => '2021-01-17 17:50:12',
    'ip' => '93.80.3.62',
    'isPreauth' => '0',
    'operator' => 'mts',
    'orderCurrency' => 'RUB',
    'orderSum' => '10.00',
    'payerCurrency' => 'RUB',
    'payerSum' => '10.00',
    'paymentType' => 'mc',
    'phone' => '0',
    'profit' => '8',
    'projectId' => '123456',
    'signature' => '65f56854115sadfdfa103798a8c34b6cd0ad55ccf9caf91f70e7745ad8bd1e76f93a54aad',
    'sum' => '10',
    'test' => '1',
    'unitpayId' => '175',
  ),
)

Вот таким образом у меня правильно формируется подпись, но только для одного метода платежа. Если метод платежа меняется, то параметры могут немного меняться, поэтому подпись уже неверна. Кусок кода формирования подписи я выделил комментариями.

        $canal = 'unitpay';
        $amount_value = $_GET['params']['payerSum']; //сумма платежа
        $payment_id_unitpay = $_GET['params']['account']; // № транзакции
        $CURRENCY = Config_Payment::UNITPAY_CURRENCY; // валюта. Для проверки платежа
        $UNITPAY_PROJECTID = Config_Payment::UNITPAY_PROJECTID; // номер магазина. Для проверки платежа
        $secret_key = Config_Payment::UNITPAY_SECRETKEY; // секретный ключ
        if (stripos($payment_id_unitpay, ':')) { // передавали uid и транзакцию в одном параметре. Теперь разбираем из ответа
            $payment_id_unitpay_2 = explode(":", $payment_id_unitpay);
            $account = (int) $payment_id_unitpay_2[0]; // id
            $billId = (int) $payment_id_unitpay_2[1]; // транзакция
        }
    
 

    
        // sha256. Старт. Написано для теста. При типе платежа "Мобильная коммерция" ключ совпадает. При других типах массив имеет другие параметры.




        $method = $_GET['method'];
        $date = $_GET['params']['date'];
        $ip = $_GET['params']['ip'];
        $isPreauth = $_GET['params']['isPreauth'];
        $operator = $_GET['params']['operator'];
        $orderCurrency = $_GET['params']['orderCurrency'];
        $orderSum = $_GET['params']['orderSum'];
        $payerCurrency = $_GET['params']['payerCurrency'];
        $payerSum = $_GET['params']['payerSum'];
        $paymentType = $_GET['params']['paymentType'];
        $phone = $_GET['params']['phone'];
        $profit = $_GET['params']['profit'];
        $projectId = $_GET['params']['projectId'];
        $sum = $_GET['params']['sum'];
        $test = $_GET['params']['test'];
        $unitpayId = $_GET['params']['unitpayId'];
    
        $sha256_hash_header = $_GET['params']['signature'];
        function getFormSignature($method, $payment_id_unitpay, $date, $ip, $isPreauth, $operator, $orderCurrency, $orderSum, $payerCurrency, $payerSum, $paymentType, $phone, $profit, $projectId, $sum, $test, $unitpayId, $secret_key) {
                $hashStr = $method.'{up}'.$payment_id_unitpay.'{up}'.$date.'{up}'.$ip.'{up}'.$isPreauth.'{up}'.$operator.'{up}'.$orderCurrency.'{up}'.$orderSum.'{up}'.$payerCurrency.'{up}'.$payerSum.'{up}'.$paymentType.'{up}'.$phone.'{up}'.$profit.'{up}'.$projectId.'{up}'.$sum.'{up}'.$test.'{up}'.$unitpayId.'{up}'.$secret_key;
                return hash('sha256', $hashStr);
        }
        $sha256_hash = getFormSignature($method, $payment_id_unitpay, $date, $ip, $isPreauth, $operator, $orderCurrency, $orderSum, $payerCurrency, $payerSum, $paymentType, $phone, $profit, $projectId, $sum, $test, $unitpayId, $secret_key);
    



// sha256. Финиш
    



        if ($sha256_hash_header == $sha256_hash && !empty($sha256_hash_header)) { // Сравнение sha256
            $userID = (int) $account;
            $defint = (int) $billId;
            $amount = $amount_value;
        } else {
            die(json_encode(array("error" => array("message" => "Invalid data"))));
        }
    
        //if($_GET['params']['sum'] != (float) $_GET['params']['orderSum']) {
        //    die(json_encode(array("error" => array("message" => "Invalid amount transferred "))));
        //}
    
        if($_GET['params']['orderCurrency'] != $CURRENCY) {
            die(json_encode(array("error" => array("message" => "Invalid transferred currency"))));
        }

        if($_GET['params']['projectId'] != $UNITPAY_PROJECTID) {
            die(json_encode(array("error" => array("message" => "Invalid project id"))));
        }
    
        if($_GET['method'] == 'check'){
            die(json_encode(array("result" => array("message" => "Successful check"))));
        }
    
        if($_GET['method'] == 'preauth'){
            die(json_encode(array("result" => array("message" => "Pre-authorization. Waiting for payment"))));
        }
    
        if($_GET['method'] == 'error'){
            die(json_encode(array("result" => array("message" => "Payment error. Expectation"))));
        }
    
        if($_GET['method'] == 'pay'){
            $this->addBalance($canal, $userID, $amount, $defint); // Начисляем баланс
            die(json_encode(array("result" => array("message" => "Success"))));
        }

Вот кусок кода из sdk unitpay, но у себя подобное я сделать не смог:

private $params = array();
function getSignature(array $params, $method = null)
    {
        ksort($params);
        unset($params['sign']);
        unset($params['signature']);
        array_push($params, $this->secretKey);

        if ($method) {
            array_unshift($params, $method);
        }

        return hash('sha256', join('{up}', $params));
    }

list($method, $params) = array($_GET['method'], $_GET['params']);

        if (!in_array($method, $this->supportedPartnerMethods)) {
            throw new UnexpectedValueException('Method is not supported');
        }

        if (!isset($params['signature']) || $params['signature'] != $this->getSignature($params, $method)) {
            throw new InvalidArgumentException('Wrong signature');
        }

https://help.unitpay.ru/payments/payment-handler


Ответы (1 шт):

Автор решения: ceg
     $method = filter_input(INPUT_GET, 'method');
    $params = filter_input(INPUT_GET, 'params', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
    $secret_key = Config_Payment::UNITPAY_SECRETKEY;

    ksort($params);
    unset($params['sign']);
    unset($params['signature']);
    array_push($params, $secret_key);
    if( $method )
        array_unshift($params, $method);

    $sha256_hash = hash('sha256', join('{up}', $params));

Источник: https://forum.antichat.ru/threads/482659/#post-4441385 (мне ответили на форуме)

→ Ссылка