Как получить хеш HMAC SHA-1 на 1С 8 (x64), чтобы он совпадал с онлайн-генераторами

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

При интеграции 1С:Предприятие с внешними веб-сервисами, платежными шлюзами или API социальных сетей программисты часто сталкиваются с необходимостью формирования подписи сообщения по алгоритму HMAC SHA-1. Казалось бы, задача тривиальная, но на практике часто возникает ситуация, когда полученный в 1С хеш не совпадает с результатом онлайн-генераторов или требованиями стороннего сервиса. Ситуация осложняется при работе на 64-битных серверах, где старые COM-компоненты (например, CAPICOM) не поддерживаются.

В этой статье мы подробно разберем, почему возникают расхождения, как правильно обрабатывать длинные ключи и как реализовать надежное решение, работающее на платформе 1С 8.3 x64.

Различие между SHA-1 и HMAC SHA-1

Прежде всего, проанализируем фундаментальную ошибку: использование встроенного объекта 1С ХешированиеДанных для получения HMAC. Рассмотрим код, который часто ошибочно принимают за решение:


ХФ = Новый ХешированиеДанных(ХешФункция.SHA1);
ХФ.Добавить(Строка);
Результат = Base64Строка(ХФ.ХешСумма);

Проблема заключается в том, что ХешированиеДанных вычисляет обычный хеш SHA-1. Алгоритм HMAC (Hash-based Message Authentication Code) — это не просто хеширование текста, это криптографический алгоритм, который использует секретный ключ. Он строится по формуле: SHA1((K XOR opad) + SHA1((K XOR ipad) + message)). Попытка получить HMAC простым добавлением ключа к строке перед хешированием также не даст верного результата.

Проблема длинных ключей и стандарт RFC 2104

Выясним причину, по которой «самописные» функции в 1С могут работать с короткими ключами, но выдавать неверный результат с длинными. Согласно стандарту RFC 2104, процедура подготовки ключа (Key) строго регламентирована:

  1. Если длина ключа меньше или равна размеру блока хеш-функции (для SHA-1 это 64 байта), ключ используется как есть (дополняется нулями до 64 байт).
  2. Если длина ключа больше 64 байт, ключ сначала должен быть пропущен через функцию SHA-1. Полученный результат (20 байт) становится новым ключом, который затем уже используется в алгоритме.

Если ваша реализация в 1С не учитывает это условие, то на длинных ключах (как в примере из темы форума) хеш никогда не совпадет с эталонным.

Влияние кодировки и скрытых символов

Посмотрим на ситуацию со стороны обработки строк. 1С хранит строки в формате UTF-16, в то время как большинство внешних систем и онлайн-генераторов ожидают UTF-8. Кроме того, при копировании ключей из браузеров или документации в строку могут попасть невидимые символы, такие как C2 AD (мягкий перенос) или Zero Width Space.

Проанализируем пример из обсуждения: ключ содержит последовательности, которые визуально выглядят как обычный текст, но при детальном рассмотрении содержат символы с кодами, отличными от стандартных. Перед вычислением хеша крайне важно очистить строку ключа и принудительно перевести её в кодировку UTF-8.

Решение для 1С 8.3 x64 с использованием .NET

Поскольку мы работаем в среде Windows (x64), наиболее эффективным и надежным способом будет обращение к системной библиотеке System.Security.Cryptography через механизм COM. Этот метод гарантирует полное соответствие стандартам RFC и корректную работу с ключами любой длины.

Разберем по шагам реализацию функции на стороне сервера:


Функция ПолучитьHMAC_SHA1(ТекстДанных, СекретныйКлюч) Экспорт
    
    // Используем мост через COM-объект для доступа к .NET
    Текст = Новый COMОбъект("System.Text.UTF8Encoding");
    Криптография = Новый COMОбъект("System.Security.Cryptography.HMACSHA1");
    
    // Преобразуем входящие строки 1С (UTF-16) в массивы байтов UTF-8
    ДанныеБайты = Текст.GetBytes_4(ТекстДанных);
    КлючБайты = Текст.GetBytes_4(СекретныйКлюч);
    
    // Устанавливаем ключ. .NET сам выполнит хеширование ключа, если он > 64 байт
    Криптография.Key = КлючБайты;
    
    // Вычисляем хеш-сумму
    ХешБайты = Криптография.ComputeHash_2(ДанныеБайты);
    
    // Преобразуем результат в Base64 для удобства передачи
    Возврат Base64Строка(ХешБайты);
    
КонецФункции

В данном примере метод GetBytes_4 используется для получения массива байтов. Обратите внимание, что объект HMACSHA1 в .NET автоматически берет на себя всю сложность реализации RFC 2104, включая XOR-операции с ipad и opad.

Альтернативное решение на чистом 1С

Если по каким-то причинам использование COM-объектов невозможно (например, работа в среде Linux), нам необходимо реализовать алгоритм вручную. Рассмотрим логику подготовки ключа, которую нужно добавить в вашу функцию:


// Пример подготовки ключа в 1С
Если КлючБайты.Количество() > 64 Тогда
    Хеширование = Новый ХешированиеДанных(ХешФункция.SHA1);
    Хеширование.Добавить(КлючБайты);
    КлючБайты = Хеширование.ХешСумма; // Получаем 20 байт
КонецЕсли;

// Далее ключ дополняется нулями до 64 байт и выполняются XOR операции

Важно помнить, что для выполнения побайтовых операций XOR в 1С 8.3 лучше всего использовать объект COMОбъект("Число") или преобразовывать данные в массив чисел, так как встроенных средств для работы с битами в языке 1С практически нет (до появления расширений в последних версиях платформы).

Итоговый чек-лист для проверки

Если ваш хеш всё еще не совпадает, выполните следующие действия:

  1. Проверьте тип результата: Онлайн-генераторы могут выдавать результат в формате HEX (шестнадцатеричный) или Base64. В 1С ХешСумма — это ДвоичныеДанные, которые можно преобразовать в HEX через СтрЗаменить(Строка(ХешСумма), " ", "") или в Base64Строка().
  2. Кодировка: Убедитесь, что и ключ, и сообщение переведены в UTF-8 без BOM.
  3. Спецсимволы: Проверьте наличие символов переноса строк (CRLF vs LF). В 1С это часто Символы.ПС, а веб-сервис может ожидать только \n.
  4. Длина ключа: Если ключ длиннее 64 символов, убедитесь, что ваш алгоритм предварительно хеширует его.

Используя системные библиотеки .NET, вы минимизируете риск ошибок реализации и обеспечиваете максимальную производительность вашего кода на платформе 1С 8.3 x64.

← На главную