Как реализовать алгоритм HMACSHA256 в 1С:Предприятие 8.2 и 8.3

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с современными веб-сервисами, платежными шлюзами или биржами часто возникает необходимость формирования подписи запроса по алгоритму HMACSHA256. Если в последних версиях платформы 1С 8.3 (начиная с 8.3.10) появились встроенные средства криптографии, то в версии 1С 8.2 и ранних сборках 8.3 программисты сталкиваются с отсутствием прямой поддержки этой функции.

В этой статье мы подробно разберем, как реализовать данный алгоритм, используя возможности .NET Framework через COM-объекты, и выясним, почему стандартные попытки преобразования результата часто приводят к неверному хешу, отличающемуся от функции hash_hmac в PHP.

Разбор архитектуры решения через COM-объекты

Поскольку в 1С 8.2 нет встроенного объекта для HMAC, мы воспользуемся библиотекой mscorlib.dll, которая входит в состав .NET Framework и доступна на большинстве серверов и рабочих станций под управлением Windows. Рассмотрим основные объекты, которые нам понадобятся:

Важное замечание: При работе с .NET объектами через COM-соединение в 1С используется позднее связывание. Из-за особенностей реализации COM, если метод в .NET имеет перегрузки (несколько методов с одним именем, но разными параметрами), к имени метода в 1С добавляется порядковый номер (например, GetBytes_4 или ComputeHash_2). Это критически важный момент, без которого код не будет работать.

Реализация функции получения HEX-строки (аналог PHP hash_hmac)

Рассмотрим ситуацию, когда нам нужно получить результат в виде шестнадцатеричной строки (Hex). Проанализируем пример кода, который подготавливает данные и вычисляет хеш.


Функция ПолучитьHMACSHA256_Hex(Знач СтрокаДанных, Знач СекретныйКлюч) Экспорт
    
    // Создаем объект кодировки для корректного преобразования строк
    ТекстКодировка = Новый COMОбъект("System.Text.UTF8Encoding");
    
    // Инициализируем объект алгоритма
    Криптография = Новый COMОбъект("System.Security.Cryptography.HMACSHA256");
    
    // Устанавливаем секретный ключ. Метод GetBytes_4 возвращает массив байт ключа
    Криптография.Key = ТекстКодировка.GetBytes_4(СекретныйКлюч);
    
    // Вычисляем хеш. Метод возвращает массив байт (Variant Array)
    МассивБайтХеш = Криптография.ComputeHash_2(ТекстКодировка.GetBytes_4(СтрокаДанных)).Выгрузить();
    
    // Преобразуем массив байт в шестнадцатеричную строку
    РезультатHex = "";
    Для Каждого Байт Из МассивБайтХеш Цикл
        // Форматируем каждый байт как двухсимвольное hex-значение
        СимволHex = НРег(Сред(СкалярноеЗначениеВHex(Байт), 1, 2));
        Если СтрДлина(СимволHex) < 2 Тогда
            СимволHex = "0" + СимволHex;
        КонецЕсли;
        РезультатHex = РезультатHex + СимволHex;
    КонецЦикла;
    
    Возврат РезультатHex;
    
КонецФункции

Функция СкалярноеЗначениеВHex(Знач Число)
    // Вспомогательная функция для перевода числа в 16-ричную систему
    База = 16;
    Результат = "";
    Пока Число > 0 Цикл
        Остаток = Число % База;
        Результат = Сред("0123456789abcdef", Остаток + 1, 1) + Результат;
        Число = Цел(Число / База);
    КонецЦикла;
    Возврат ?(Результат = "", "00", Результат);
КонецФункции

В данном примере мы используем UTF8Encoding, так как большинство внешних API (и PHP по умолчанию) ожидают данные именно в этой кодировке. Если передать строку напрямую, 1С передаст её в формате Unicode (UTF-16), что приведет к неверному результату хеширования.

Проблема преобразования в Base64 и её решение

Одной из самых частых ошибок, описанных на форумах, является неправильное кодирование полученного хеша в Base64. Многие программисты сначала переводят массив байт в Hex-строку (например, "41c9dd97..."), а затем пытаются кодировать эту строку в Base64. Это в корне неверно!

Для корректного результата (аналог base64_encode(hash_hmac(...)) в PHP) необходимо кодировать в Base64 именно бинарные данные (массив байт), а не их строковое представление. Рассмотрим наиболее элегантный способ сделать это в 1С 8.2 без использования временных файлов, напрямую через .NET.


Функция ПолучитьHMACSHA256_Base64(Знач СтрокаДанных, Знач СекретныйКлюч) Экспорт
    
    ТекстКодировка = Новый COMОбъект("System.Text.UTF8Encoding");
    Криптография = Новый COMОбъект("System.Security.Cryptography.HMACSHA256");
    
    // Преобразуем входные данные в байты
    БайтыКлюча = ТекстКодировка.GetBytes_4(СекретныйКлюч);
    БайтыДанных = ТекстКодировка.GetBytes_4(СтрокаДанных);
    
    Криптография.Key = БайтыКлюча;
    
    // Вычисляем хеш в виде массива байт
    ХешБайт = Криптография.ComputeHash_2(БайтыДанных);
    
    // Используем .NET объект System.Convert для получения Base64 напрямую из массива байт
    Конвертер = Новый COMОбъект("System.Convert");
    РезультатBase64 = Конвертер.ToBase64String(ХешБайт);
    
    Возврат РезультатBase64;
    
КонецФункции

Этот метод гарантирует 100% совпадение с результатом PHP. Длина строки SHA256 в формате Base64 всегда будет составлять 44 символа (включая знаки заполнения = в конце).

Почему результаты в 1С и PHP могут не совпадать?

Если вы внедрили код, но подпись всё равно не проходит проверку, проанализируем основные причины расхождений:

  1. Кодировка исходной строки. Если ваша строка содержит кириллицу, убедитесь, что вы используете UTF8Encoding. В PHP строка — это просто набор байтов, и если PHP-скрипт сохранен в UTF-8, он будет хешировать байты UTF-8. 1С работает с Unicode, поэтому явная конвертация обязательна.
  2. Порядок параметров. В PHP функция hash_hmac принимает параметры в порядке: алгоритм, данные, ключ. В методах .NET мы сначала присваиваем ключ объекту, а затем передаем данные в метод вычисления. Проверьте, не перепутаны ли местами ключ и данные.
  3. Параметр raw_output в PHP. Функция hash_hmac('sha256', $data, $key, true) возвращает бинарные данные. Именно их нужно кодировать в Base64. Если четвертый параметр в PHP равен false, возвращается Hex-строка. Выясните, какой формат ожидает принимающая сторона.
  4. Метод Base64 в 1С. Встроенная функция Base64Строка() работает с объектом ДвоичныеДанные. Если вы пытаетесь создать ДвоичныеДанные из Hex-строки через временный файл (как делал автор темы в Сообщении 4), вы записываете в файл текстовые символы "4", "1", "c"... в кодировке ANSI, а не реальные байты хеша. Это главная причина ошибок.

Альтернативный способ для 1С 8.3 (новые версии)

Если вы работаете на платформе выше 8.3.10, вы можете рассмотреть использование объекта ХешированиеДанных, однако стоит помнить, что он предназначен для обычного хеширования (SHA1, SHA256 и т.д.), а не для HMAC (хеширование с ключом). Для реализации HMAC на чистом 1С без COM-объектов пришлось бы вручную реализовывать алгоритм исключающего ИЛИ (XOR) с внутренними и внешними отступами (ipad/opad). Использование COMОбъект("System.Security.Cryptography.HMACSHA256") остается самым простым и надежным способом для Windows-окружения.

Таким образом, мы выяснили, что секрет успеха заключается в трех вещах: использовании правильных COM-методов .NET, строгом соблюдении кодировки UTF-8 и передаче «сырых» байтов хеша в конвертер Base64. Следуя этим правилам, вы сможете организовать надежное взаимодействие 1С с любыми современными веб-сервисами.

← На главную