Первое шифрование

Итак нам нужно зашифровать запрос. 

Ключи необходимые для шифрования запроса: https://nanokassa.ru/integration/documentation/publichnye-rsa-klyuchi/

Итак нам нужно зашифровать вот такой запрос:

{
    "kassaid": "123456",
    "kassatoken": "12345678912345678912345678912345",
    "cms": "ss7-7.3.0.209",
    "check_send_type": "email",
    "products_arr": [{
        "name_tovar": "\u041a\u0430\u0440\u0442\u043e\u043d\u043d\u0430\u044f \u043a\u043e\u0440\u043e\u0431\u043a\u0430 2, 11112",
        "price_piece_bez_skidki": 7744,
        "skidka": 1297,
        "kolvo": 2,
        "price_piece": 7095,
        "summa": 14191,
        "stavka_nds": 6,
        "priznak_sposoba_rascheta": 4,
        "priznak_predmeta_rascheta": 1,
        "priznak_agenta": "none",
        "phone_oper_perevoda": "",
        "operation_plat_agenta": "",
        "phone_oper_priem_plat": "",
        "name_oper_perevoda": "",
        "address_oper_perevoda": "",
        "inn_oper_perevoda": "",
        "phone_postavshika": "",
        "name_postavshika": "",
        "discount": {
            "type": "amount",
            "value": 12.97
        }
    }, {
        "name_tovar": "\u0423\u043f\u0430\u043a\u043e\u0432\u043a\u0430",
        "price_piece_bez_skidki": 155,
        "skidka": 26,
        "kolvo": 2,
        "price_piece": 142,
        "summa": 284,
        "stavka_nds": 6,
        "priznak_sposoba_rascheta": 4,
        "priznak_predmeta_rascheta": 4,
        "priznak_agenta": "none",
        "phone_oper_perevoda": "",
        "operation_plat_agenta": "",
        "phone_oper_priem_plat": "",
        "name_oper_perevoda": "",
        "address_oper_perevoda": "",
        "inn_oper_perevoda": "",
        "phone_postavshika": "",
        "name_postavshika": "",
        "discount": {
            "type": "amount",
            "value": 0.26
        }
    }, {
        "name_tovar": "\u041a\u0430\u0440\u0442\u043e\u043d\u043d\u0430\u044f \u043a\u043e\u0440\u043e\u0431\u043a\u0430 2, 11112",
        "price_piece_bez_skidki": 2277,
        "skidka": 191,
        "kolvo": 1,
        "price_piece": 2086,
        "summa": 2086,
        "stavka_nds": 6,
        "priznak_sposoba_rascheta": 4,
        "priznak_predmeta_rascheta": 1,
        "priznak_agenta": "none",
        "phone_oper_perevoda": "",
        "operation_plat_agenta": "",
        "phone_oper_priem_plat": "",
        "name_oper_perevoda": "",
        "address_oper_perevoda": "",
        "inn_oper_perevoda": "",
        "phone_postavshika": "",
        "name_postavshika": "",
        "discount": {
            "type": "amount",
            "value": 1.91
        }
    }, {
        "name_tovar": "\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430: PickPoint",
        "price_piece": 30000,
        "summa": 30000,
        "kolvo": 1,
        "stavka_nds": 6,
        "priznak_sposoba_rascheta": 4,
        "priznak_predmeta_rascheta": 1,
        "priznak_agenta": "none",
        "phone_oper_perevoda": "",
        "operation_plat_agenta": "",
        "phone_oper_priem_plat": "",
        "name_oper_perevoda": "",
        "address_oper_perevoda": "",
        "inn_oper_perevoda": "",
        "phone_postavshika": "",
        "name_postavshika": "",
        "deliveryposition": "yes"
    }],
    "oplata_arr": {
        "rezhim_nalog": "2",
        "money_nal": 0,
        "money_electro": 46561,
        "money_predoplata": 0,
        "money_postoplata": 0,
        "money_vstrecha": 0,
        "kassir_inn": "",
        "kassir_fio": "",
        "client_email": "[email protected]",
        "client_phone": "123"
    },
    "itog_arr": {
        "priznak_rascheta": 1,
        "itog_cheka": 46561
    }

Итак вот этот большой запрос после шифрования должен превратиться вот в такой небольшой запрос:

{
    "ab":"GYBhagdYGWgahjGDHASgdjhas...ASDGd", 
    "de":"GYBhagdYGWgahjGDHASgdjhas...ASDGd", 
    "kassaid":"123456", 
    "kassatoken":"3212312312312",
    "check_type":"standart",
    "rid":"2020_123456789abc123456789123456789abc"
    "test":"1"
}

Разберем, что здесь что.

Переменные kassaid и kassatoken - данные для авторизации.

В переменной test мы прописываем, тестовый это запрос или «боевой». Внимание! Не забывайте его указывать! Потому, что если вы его не указали, мы автоматически считаем его тестовым и не проведем через онлайн кассы. (Возможные значения: 0; 1) (1 -запрос тестовый, 0 - запрос боевой). Этот объект придется еще раз указывать - поэтому не забывайте о нем. Зато они будут видны в личном кабинете nanokassa.ru

В переменной ab находится ключ для дешифровки пакета de. Объект ab зашифрован с помощью шифрования RSA. 

В переменной de находится основной пакет с данными. Объект de зашифрован с помощью AES256-CTR. Ключ каждый раз разный. Ключ можно узнать только расшифровав пакет ab (RSA)

В переменной check_type находится параметр типа чека. Если это чек прихода или возврата, поставьте параметр standart. Если это чек коррекции - то параметр должен быть равен korrcheck.

В переменной rid находится параметр уникальный параметр Request-ID. Он не обязателен. Подробнее про него можете прочитать тут.

Вот функции (на php) (с учетом, что установлен openssl), чтобы грамотно вам зашифровать пакеты для первого шифрования. (request показан обобщенно). Для шифрования aes256-ctr используется функция openssl_encrypt.

$request = '{
"kassaid": "123456", "kassatoken": "3212312312312", "cms":"xxx", ... "card_amount": 3934
}';
$IVdata = random_bytes(16);
$pw = random_bytes(32);
$mk = 'xxx'; // hmac контроль в формате base64
$dataAES = openssl_encrypt($request, "aes-256-ctr", $pw, OPENSSL_RAW_DATA, $IVdata);
$hmac = hash_hmac('sha512', $IVdata.$dataAES, base64_decode($mk), true);
$returnDataDE = base64_encode($hmac.$IVdata.$dataAES);

То есть строение пакета de должно быть таким. 64 байта hmac, 16 байт IVDATA, и остальные байты самого пакета.

Теперь перейдем к пакету ab. 

Вот функции (на php) (с учетом, что установлен openssl), чтобы грамотно вам зашифровать пакеты для первого шифрования. (pubkey показан обобщенно). Для шифрования RSA используется функция openssl_public_encrypt.

$pubkey = "-----BEGIN PUBLIC KEY-----
HASGDHJASGDASDSAGD .... 
SADGHASDHASJGDAHJS==
-----END PUBLIC KEY-----";
openssl_public_encrypt($pw, $ab_rsa, $pubkey, OPENSSL_PKCS1_OAEP_PADDING)
$ab = base64_encode ($ab_rsa);
$returnDataAB = $ab;

Теперь мы можем уже понять, как получить вот такой пакет. 

{    
    "ab":"GYBhagdYGWgahjGDHASgdjhas...ASDGd",     
    "de":"GYBhagdYGWgahjGDHASgdjhas...ASDGd",     
    "kassaid":"123456",     
    "kassatoken":"3212312312312",
    "check_type":"standart",
    "test":"1"
}

Перейдем ко второму шифрованию.