При интеграции 1С с современными веб-сервисами, платежными шлюзами или биржами часто возникает необходимость формирования подписи запроса по алгоритму HMACSHA256. Если в последних версиях платформы 1С 8.3 (начиная с 8.3.10) появились встроенные средства криптографии, то в версии 1С 8.2 и ранних сборках 8.3 программисты сталкиваются с отсутствием прямой поддержки этой функции.
В этой статье мы подробно разберем, как реализовать данный алгоритм, используя возможности .NET Framework через COM-объекты, и выясним, почему стандартные попытки преобразования результата часто приводят к неверному хешу, отличающемуся от функции hash_hmac в PHP.
Поскольку в 1С 8.2 нет встроенного объекта для HMAC, мы воспользуемся библиотекой mscorlib.dll, которая входит в состав .NET Framework и доступна на большинстве серверов и рабочих станций под управлением Windows. Рассмотрим основные объекты, которые нам понадобятся:
System.Text.UTF8Encoding — для корректного преобразования строк 1С в массив байтов в кодировке UTF-8.System.Security.Cryptography.HMACSHA256 — непосредственно класс, реализующий алгоритм хеширования.System.Convert — для быстрого и правильного преобразования результата в формат Base64.Важное замечание: При работе с .NET объектами через COM-соединение в 1С используется позднее связывание. Из-за особенностей реализации COM, если метод в .NET имеет перегрузки (несколько методов с одним именем, но разными параметрами), к имени метода в 1С добавляется порядковый номер (например, GetBytes_4 или ComputeHash_2). Это критически важный момент, без которого код не будет работать.
Рассмотрим ситуацию, когда нам нужно получить результат в виде шестнадцатеричной строки (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. Многие программисты сначала переводят массив байт в 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 символа (включая знаки заполнения = в конце).
Если вы внедрили код, но подпись всё равно не проходит проверку, проанализируем основные причины расхождений:
UTF8Encoding. В PHP строка — это просто набор байтов, и если PHP-скрипт сохранен в UTF-8, он будет хешировать байты UTF-8. 1С работает с Unicode, поэтому явная конвертация обязательна.hash_hmac принимает параметры в порядке: алгоритм, данные, ключ. В методах .NET мы сначала присваиваем ключ объекту, а затем передаем данные в метод вычисления. Проверьте, не перепутаны ли местами ключ и данные.hash_hmac('sha256', $data, $key, true) возвращает бинарные данные. Именно их нужно кодировать в Base64. Если четвертый параметр в PHP равен false, возвращается Hex-строка. Выясните, какой формат ожидает принимающая сторона.Base64Строка() работает с объектом ДвоичныеДанные. Если вы пытаетесь создать ДвоичныеДанные из Hex-строки через временный файл (как делал автор темы в Сообщении 4), вы записываете в файл текстовые символы "4", "1", "c"... в кодировке ANSI, а не реальные байты хеша. Это главная причина ошибок.Если вы работаете на платформе выше 8.3.10, вы можете рассмотреть использование объекта ХешированиеДанных, однако стоит помнить, что он предназначен для обычного хеширования (SHA1, SHA256 и т.д.), а не для HMAC (хеширование с ключом). Для реализации HMAC на чистом 1С без COM-объектов пришлось бы вручную реализовывать алгоритм исключающего ИЛИ (XOR) с внутренними и внешними отступами (ipad/opad). Использование COMОбъект("System.Security.Cryptography.HMACSHA256") остается самым простым и надежным способом для Windows-окружения.
Таким образом, мы выяснили, что секрет успеха заключается в трех вещах: использовании правильных COM-методов .NET, строгом соблюдении кодировки UTF-8 и передаче «сырых» байтов хеша в конвертер Base64. Следуя этим правилам, вы сможете организовать надежное взаимодействие 1С с любыми современными веб-сервисами.