SHA-1: использование и известные ограничения

SHA-1 в криптографии представляет собой хеш-функцию, формирующую 160-битное (20-байтовое) значение фиксированной длины из входных данных произвольного размера. Несмотря на историческую популярность, сегодня SHA-1 считается криптографически небезопасным, однако в реальных проектах на JavaScript, особенно при работе с библиотекой Jsrsasign, он всё ещё встречается в легаси-системах и некоторых сценариях проверки целостности.

Библиотека Jsrsasign предоставляет несколько уровней работы с SHA-1: от простого хеширования строк до интеграции в цифровые подписи (например, RSA + SHA-1).

Простейшее хеширование строки

Для получения SHA-1 хеша строки можно использовать утилитарные функции:

const hash = KJUR.crypto.Util.sha1("Hello world");
console.log(hash);

Результат — шестнадцатеричная строка длиной 40 символов.

Аналогично можно использовать объект MessageDigest:

const md = new KJUR.crypto.MessageDigest({alg: "sha1"});
md.updateString("Hello world");
const hash = md.digest();
console.log(hash);

Оба подхода дают идентичный результат, однако MessageDigest удобнее при поэтапной обработке данных.

SHA-1 в цифровых подписях

Наиболее распространённое применение SHA-1 в Jsrsasign — подпись данных с использованием RSA.

Пример формирования подписи:

const sig = new KJUR.crypto.Signature({alg: "SHA1withRSA"});

sig.init(privateKeyPem);
sig.updateString("Data to sign");

const signature = sig.sign();
console.log(signature);

Проверка подписи:

const sig = new KJUR.crypto.Signature({alg: "SHA1withRSA"});

sig.init(publicKeyPem);
sig.updateString("Data to sign");

const isValid = sig.verify(signature);
console.log(isValid);

Здесь SHA-1 используется как хеш-функция внутри алгоритма подписи RSA. Это означает, что данные сначала хешируются SHA-1, а затем результат подписывается приватным ключом.

Внутреннее устройство SHA-1 в контексте Jsrsasign

SHA-1 работает через последовательную обработку блоков данных по 512 бит. В Jsrsasign реализация абстрагирована, но логика остаётся классической:

  • входные данные дополняются (padding)
  • разбиваются на блоки
  • каждый блок проходит 80 раундов преобразований
  • результат агрегируется в 5 32-битных словах

Разработчику важно не взаимодействовать с этим уровнем напрямую, но понимание структуры помогает оценивать производительность и безопасность.

Форматы вывода SHA-1

Jsrsasign возвращает SHA-1 в нескольких форматах:

  • hex (по умолчанию)
  • base64 (при дополнительной обработке)
  • raw binary (редко используется напрямую)

Пример преобразования в Base64:

const md = new KJUR.crypto.MessageDigest({alg: "sha1"});
md.updateString("Hello world");
const hex = md.digest();

const b64 = hextob64(hex);
console.log(b64);

Производительность SHA-1 в браузере и Node.js

SHA-1 является относительно быстрым алгоритмом по сравнению с SHA-256 и более современными функциями. В Jsrsasign он реализован на чистом JavaScript, что делает его:

  • менее производительным, чем нативные реализации Web Crypto API
  • достаточно быстрым для небольших данных
  • заметно медленным при обработке больших потоков

Для сравнения, Web Crypto API:

const encoder = new TextEncoder();
const data = encoder.encode("Hello world");

crypto.subtle.digest("SHA-1", data).then(hashBuffer => {
  console.log(hashBuffer);
});

В большинстве современных приложений предпочтение отдаётся именно Web Crypto API, если SHA-1 всё же используется.

Известные ограничения SHA-1

SHA-1 перестал считаться криптографически стойким после ряда атак на коллизии.

Коллизии

Коллизия — ситуация, при которой два разных входных набора данных дают одинаковый хеш.

SHA-1 больше не защищён от практических атак на коллизии. Это означает:

  • возможно создание двух разных документов с одинаковым SHA-1
  • цифровые подписи на SHA-1 могут быть подделаны при достаточных ресурсах атакующего

В 2017 году была продемонстрирована первая практическая коллизия SHA-1 (атака SHAttered), что окончательно закрепило его статус устаревшего алгоритма.

Проблемы безопасности при использовании SHA-1

Использование SHA-1 в современных системах приводит к ряду рисков:

Подделка цифровых подписей

Если система использует SHA-1 в цепочке подписания, злоумышленник может теоретически создать альтернативный документ с тем же хешем.

Уязвимость протоколов

Некоторые старые протоколы (TLS, сертификаты X.509) ранее использовали SHA-1. Поддержка таких сертификатов в современных браузерах ограничена или полностью отключена.

Деградация доверия

Даже без прямой атаки, сам факт использования SHA-1 снижает криптографическую надёжность системы.

SHA-1 и Jsrsasign в легаси-проектах

Несмотря на недостатки, SHA-1 продолжает встречаться в:

  • старых PKI-системах
  • архивных цифровых подписях
  • интеграциях с устаревшими API
  • внутренних корпоративных системах

Jsrsasign часто используется именно как средство поддержки таких систем, позволяя работать с SHA-1 без перехода на нативные API.

Рекомендованные альтернативы внутри Jsrsasign

Хотя библиотека поддерживает SHA-1, в большинстве случаев предпочтение стоит отдавать:

  • SHA-256 (SHA256withRSA)
  • SHA-384
  • SHA-512

Пример замены:

const sig = new KJUR.crypto.Signature({alg: "SHA256withRSA"});

Переход на более стойкие алгоритмы требует только изменения параметра alg, без переписывания логики работы с ключами.

Совместимость SHA-1 с экосистемой JavaScript

SHA-1 в Jsrsasign часто используется для обеспечения совместимости с:

  • Java-бэкендами
  • устаревшими OpenSSL-конфигурациями
  • внешними сервисами, не обновившими криптографические стандарты

Однако эта совместимость достигается ценой снижения безопасности, что делает SHA-1 скорее инструментом поддержки старых систем, чем частью современной криптографии.