Любой файл при хранении или передаче может повредиться: сбой сектора на диске, обрыв соединения, ошибка памяти. Чтобы не распаковывать архив впустую и не ставить битую программу, используются контрольные суммы - короткие числа, вычисленные из содержимого. Архив ZIP хранит для каждого файла значение CRC32, вычисленное при сжатии, и сравнивает его с контрольной суммой заново прочитанных данных. Если числа не совпали, архиватор сообщает о повреждении ещё до извлечения. Рядом живут криптографические хеши MD5, SHA-1 и SHA-256, которые защищают не от случайных сбоев, а от осмысленной подмены. Эта статья разбирает обе семьи механизмов: математику CRC32, устройство заголовков ZIP, свойства криптографических хешей, применение хешей в торрентах и практические команды проверки в Windows.
CRC32 как полиномиальное деление по модулю 2
Аббревиатура CRC означает cyclic redundancy check, циклический избыточный код. В основе лежит арифметика многочленов над полем из двух элементов: коэффициенты принимают значения 0 и 1, сложение выполняется операцией XOR без переносов, и вычитание совпадает со сложением. Поток байтов сообщения трактуется как один длинный многочлен, где каждый бит является коэффициентом при своей степени переменной. Этот многочлен делится на заранее выбранный порождающий многочлен, и остаток от деления, дополненный до 32 бит, становится контрольной суммой.
Стандартный многочлен CRC32, применяемый в ZIP, Ethernet, PNG и множестве других форматов, записывается в шестнадцатеричной форме как 0xEDB88320. Это перевёрнутая, отражённая форма полного многочлена 0x04C11DB7: в алгоритме биты обрабатываются справа налево, младшим битом вперёд, поэтому константа выглядит зеркально. Многочлен степени 32 подобран так, чтобы остаток чувствительно реагировал на типичные искажения данных.
Прямое деление многочленов побитно было бы медленным, поэтому практические реализации используют табличный метод. Перед работой строится таблица из 256 значений: для каждого возможного байта заранее вычислен его вклад в остаток с учётом восьми шагов сдвига и условного XOR с многочленом. Далее обработка сводится к скользящему циклу: берётся очередной байт данных, складывается по XOR со старшим байтом текущего регистра CRC, результат служит индексом в таблице, регистр сдвигается на байт влево и складывается по XOR с табличным значением. Псевдокод прост: crc = table[(crc ^ byte) & 0xFF] ^ (crc >> 8). По одной итерации на байт исходное сообщение превращается в четырехбайтовое число. Перед началом регистр инициализируется единицами, а в конце инвертируется, что убирает нечувствительность к ведущим нулевым байтам.
Гарантии обнаружения ошибок и пределы CRC32
Полиномиальная природа кода даёт строгие математические гарантии. Любая одиночная ошибка в одном бите меняет многочлен сообщения на слагаемое вида x в степени k, а порождающий многочлен имеет более одного ненулевого члена и не делит такое слагаемое, поэтому остаток обязательно изменится. Любая двойная ошибка на произвольных позициях тоже гарантированно обнаруживается, пока длина сообщения не превышает период многочлена. Обнаруживаются и все пакетные ошибки, то есть непрерывные серии испорченных битов длиной до 32 разрядов: такой пакет соответствует многочлену степени меньше 32 и не может быть кратен делителю без остатка. Более длинные пакеты ловятся с вероятностью 1 минус 1/2^32.
Число 1/2^32 примерно равно 2.3 на 10 в минус десятой степени - это вероятность того, что случайно повреждённое сообщение даст ту же контрольную сумму, что и оригинал. Для сетевых сбоев и царапин на диске этого запаса хватает с избытком. Однако CRC32 не является криптографическим примитивом. Он линеен: зная сообщение и его сумму, злоумышленник легко подбирает правку, которая сохранит остаток. Существуют короткие алгоритмы вычисления таких корректирующих вставок. Поэтому CRC32 отвечает только на вопрос о случайной порче и совершенно уязвим к осмысленной подделке. Там, где угроза исходит от человека, а не от физики, нужны хеши другого класса.
Контрольные суммы внутри архива ZIP
Формат ZIP хранит CRC32 несжатых данных каждого файла в двух местах. Локальный заголовок, стоящий непосредственно перед сжатыми данными, содержит поля сигнатуры, версии, метода сжатия, размеров и контрольной суммы. Однако при потоковой записи архива эти поля могут быть нулевыми: упаковщик не знает CRC, пока не сожмёт файл целиком, и тогда после данных пишется дескриптор данных с итоговыми значениями. Второй экземпляр живёт в центральном каталоге в конце архива - там каждая запись о файле дублирует CRC32, размеры и смещение локального заголовка.
Такое устройство позволяет реализовать проверку до распаковки, режим проверки целостности архива. Архиватор читает каждый файл, распаковывает его в никуда, на лету вычисляет CRC32 распакованного потока и сравнивает со значением из заголовка. Несовпадение означает повреждение архива конкретно в месте этого файла, причём остальные записи остаются доступными, потому что формат состоит из независимых блоков. Совпадение контрольных сумм центрального каталога и локальных заголовков дополнительно подтверждает структурную целостность самого архива. Интересно, что применяется CRC именно несжатых данных: проверка ловит не только порчу архива на диске, но и часть ошибок самого кодека при распаковке.
Криптографические хеши MD5 SHA-1 и SHA-256
Криптографический хеш - это необратимая функция, отображающая данные произвольной длины на строку фиксированной длины. MD5 выдаёт 128 бит, SHA-1 выдаёт 160 бит, SHA-256 выдаёт 256 бит, что в шестнадцатеричной записи занимает 64 символа. Ключевое наблюдаемое свойство - лавинный эффект: изменение одного бита входа меняет примерно половину битов результата, и два почти одинаковых файла дают хеши без какого-либо видимого родства.
История семейства поучительна. MD5 спроектирован в начале девяностых и долго считался надёжным, однако в 2004 году были показаны практические коллизии: способы построить два разных документа с одинаковым хешем. Позже атаки удешевились до минут на обычном компьютере, и стало возможным создавать пары документов с осмысленным различием - например, поддельный цифровой сертификат. С этого момента MD5 признан сломанным для цифровых подписей и любых сценариев, где противник целенаправленно строит коллизию. SHA-1 повторил его судьбу с опозданием: в 2017 году продемонстрирована первая практическая коллизия. Тем не менее MD5 остаётся полезным там, где угрозы преднамеренной подделки нет: сверить, не повредился ли файл при копировании по сети, сравнить два каталога, отсечь дубликаты. Для случайной порчи 128 бит дают пренебрежимо малую вероятность совпадения, и считается MD5 очень быстро. SHA-256 из семейства SHA-2 на сегодня остаётся стандартом де-факто для подписей пакетов, сертификатов и контроля подлинности дистрибутивов.
Хеши работают и как инструмент против повторов, и как опознавательные знаки. Системы хранения используют хеш содержимого как адрес блока: два одинаковых файла автоматически ссылаются на один экземпляр данных, а повторная загрузка распознаётся без передачи. Вредоносное программное обеспечение опознаётся антивирусными решениями не только по сигнатурам кода, но и по базам хешей известных зловредных файлов: полный хеш файла сравнивается с чёрным списком, причём сами базы можно распространять как набор чисел, не содержащий вредоносных данных.
Почему торренты проверяют хеши кусков
Торрент-протокол передаёт один логический набор данных сотнями мелких фрагментов от множества источников одновременно, и каждый источник потенциально ненадёжен: у него может быть устаревшая версия, битый сектор или злой умысел. Поэтому метафайл торрента содержит не один общий хеш, а список хешей SHA-1 каждого куска фиксированного размера, обычно от 256 килобайт до нескольких мегабайт. Получив очередной кусок, клиент сразу считает его хеш и сравнивает со списком. Совпавший кусок принимается и становится доступным для раздачи дальше, несовпавший отбрасывается и запрашивается повторно с другого источника, а упорно отправляющий мусор узел оказывается в блокировке.
Такая поэлементная проверка даёт три эффекта. Во-первых, повреждённый фрагмент не портит весь файл: заново скачивается только кусок. Во-вторых, подмена данных посредником невозможна без подбора коллизии хеша, что для SHA-1 внутри фиксированного списка остаётся практически трудной задачей второго прообраза. В-третьих, сам набор хешей защищён корневым идентификатором торрента, поэтому достаточно получить достоверный метафайл, а остальное докачается из произвольных источников. Новое поколение формата переходит на SHA-256 и древовидную структуру хешей, которая позволяет проверять части данных, не загружая метаданные целиком. Тот же принцип блочных контрольных сумм используют системы синхронизации файлов и резервного копирования: передаются только блоки, чьи хеши различаются.
Обнаружение и исправление ошибок плюс надёжная пересылка
Важно различать два класса кодов. Контрольные суммы CRC и криптографические хеши способны только обнаруживать ошибки: они отвечают на вопрос, испорчены данные или нет, но не говорят, в каком именно бите произошёл сбой, и восстановить исходное не могут. Исправлением занимаются коды с избыточностью иного типа - коды Хэмминга, Рида-Соломона, тома восстановления в архиваторах и RAID-массивы. Там дополнительные данные размечены так, что по уцелевшему можно вычислить утраченное. Цена вопроса - заметный объём избыточности, поэтому на практике комбинируют: контрольная сумма обнаруживает, механизм повторной передачи или том восстановления исправляет.
Отдельная иллюстрация контроля целостности - пересылки двоичных данных через текстовые каналы. Кодировка base64 представляет каждые три байта четырьмя символами ограниченного алфавита из букв, цифр и пары служебных знаков, увеличивая размер на треть, но гарантируя, что ни один символ не будет перетолкован промежуточным оборудованием: старые почтовые шлюзы могли срезать старший бит, менять переводы строк или трактовать управляющие коды. Само по себе base64 не является ни шифрованием, ни проверкой - это лишь безопасная упаковка. Однако открытый текст и строка base64 однозначно связаны, поэтому в паре с хешем исходных данных получатель может проверить, что текст прошёл канал без искажений: достаточно декодировать строку и сравнить хеш. Та же мысль лежит в основе контрольных сумм писем и вложений в почтовых стандартах.
Практика проверки файлов в Windows
Проверить хеш файла можно штатными средствами системы, ничего не устанавливая:
- certUtil -hashfile имя_файла SHA256 - встроенная утилита выводит хеш указанного алгоритма, поддерживаются MD2, MD4, MD5, SHA1, SHA256, SHA384 и SHA512;
- Get-FileHash имя_файла -Algorithm SHA256 - командлет PowerShell, удобный для скриптов и пакетной сверки целых каталогов;
- fciv - классическая утилита Microsoft для вычисления MD5 и SHA-1 с возможностью сохранять базу хешей в XML и потом проверять каталог на изменения;
- архиваторы предлагают пункт проверки архива, который пересчитывает CRC32 всех записей без извлечения на диск.
Типовой сценарий выглядит так. Рядом с загружаемым файлом распространитель публикует эталонный хеш, обычно SHA-256. После загрузки вычисляется локальный хеш и сравнивается посимвольно с эталоном. Совпадение подтверждает и целостность, и, если эталон получен по доверенному каналу, подлинность. Несовпадение означает однозначно: файл загружать заново, распаковывать и запускать его нельзя. При массовых проверках удобно сохранить вывод Get-FileHash в файл и затем сравнить каталоги через скрипт, отсекая изменённые и недостающие объекты.
Подведём итог. CRC32 - быстрый полиномиальный код для случайных ошибок, встроенный в ZIP, сетевые кадры и графические форматы. MD5 и SHA-1 оставлены в арсенале как скоростные индикаторы порчи там, где нет злоумышленника, а доверие обеспечивает SHA-256. Вместе эти короткие числа образуют невидимый каркас цифровой надёжности: архив отказывается распаковывать битое, торрент перекачивает испорченный кусок, хранилище не дублирует одинаковые файлы, а пользователь за секунду убеждается, что скачал именно то, что опубликовал автор.