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

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

Ключи необходимые для шифрования запроса: 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": "support@nanokassa.ru",
        "client_phone": "123"
    },
    "itog_arr": {
        "priznak_rascheta": 1,
        "itog_cheka": 46561
    }

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

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

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

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

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

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

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

Вот функции (на 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",     
    "test":"1"
}

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