Главная > Разное > Введение в криптографию
<< Предыдущий параграф
Следующий параграф >>
<< Предыдущий параграф Следующий параграф >>
Макеты страниц

3. Как зашифровать файл?

Руки прочь от моих файлов!

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

Вы, конечно, можете объяснить брату, что он не прав, подкрепив свои слова парой подзатыльников и другими весомыми аргументами. Это называется административные меры защиты.

Вы можете поставить пароль на включение компьютера. Как думаете, сколько времени продержится такая защита? Правильно. Дня три-четыре. Потом ваш брат замучает вас просьбами разрешить ему поиграть в WarCraft, и вам придется поделиться с ним паролем.

Было бы хорошо сделать так, чтобы ваш брат мог бы беспрепятственно играть в любимые игры, а доступ к чужим файлам был бы для него закрыт. Это называется разграничение доступа.

Как же организовать разграничение доступа на своем компьютере? Если бы у вас была установлена не Windows 95, a Windows NT или UNIX, вы легко могли бы ограничить доступ к своим файлам. В UNIX вам пришлось бы набрать команду chmod с нужными параметрами, а в Windows NT хватило бы нескольких движений мышью. Но у вас стоит Windows 95, a Windows 95 разграничение доступа не поддерживает. Так что же вам делать? Неужели нельзя защитить свои файлы от других пользователей?

Можно. Тут нам на помощь приходит криптография. Если вы не хотите, чтобы другие читали ваш файл, этот файл нужно зашифровать. Пусть его теперь читают все кому не лень. Все равно, если

кто-то, кроме вас, прочитает этот файл, он увидит не содержимое файла, а шифртекст. Конечно, используемый шифр должен быть достаточно стойким.

Как вводить ключ?

Как вы собираетесь вводить ключ в программу шифрования? Проще всего — с клавиатуры. Именно этот вариант реализован в большинстве готовых программ, и знакомство с ними начинается с вежливого приглашения: «enter your password: ... ». Только имейте в виду, что пароль, вводимый с клавиатуры, можно подсмотреть. Если программа шифрования при вводе пароля отображает его на экране, такой программой лучше не пользоваться. Когда при зашифровании файла вы вводите пароль, он тоже не должен отображаться на экране.

А что случится, если при вводе пароля вы случайно нажали не ту клавишу? Вы думаете, что ввели один пароль, а на самом деле ввели другой. Пробуете расшифровать файл, а программа говорит: «Пароль неправильный». Чтобы такого не было, обычно программы шифрования при вводе пароля для зашифрования файла просят ввести пароль дважды. Если пользователь в первый раз ввел один пароль, а во второй раз — другой, значит, по крайней мере один раз он ошибся. А если оба раза пользователь ввел одно и то же, значит, все нормально. Вряд ли пользователь дважды ошибется одинаково.

Как проверять правильность ключа?

Кстати, а как программа при расшифровании файла определяет, что пароль неправильный? По-разному. Некоторые программы вообще не проверяют правильность пароля. В этом случае, если вы ввели неправильный пароль, файл как бы расшифруется, но вы увидите совсем не то, что зашифровали. Это неудобно. Предположим, вы зашифровали файл мегабайт в 50 с помощью алгоритма ГОСТ. Сколько времени он будет расшифроваться? Если у вас дома стоит обычный Pentium, то, по крайней мере, минуту. А скорее всего, минуты три. Вы все это время сидите, ждете, а потом оказывается, что зря ждали — пароль-то ввели неправильный. А если вы ехе-файл неправильно расшифровали, а потом запустили на выполнение? Скорее всего, придется давить Reset. Так что лучше, когда перед расшифрованием программа проверяет правильность пароля.

Остается вопрос: как проверять правильность пароля? Можно просто вписать пароль в начало зашифрованного файла перед шифртекстом. При расшифровании вы вводите пароль, программа читает начало зашифрованного файла и сравнивает то, что вы ввели, и то, что в файле. Если совпало, значит, пароль правильный. А если не

совпало — неправильный. Просто и удобно. Только что произойдет, если кто-нибудь другой случайно просмотрит зашифрованный файл, например, с помощью Norton Commander? Весь файл — сплошная абракадабра, а в начале файла — осмысленное слово. Не нужно быть семи пядей во лбу, чтобы догадаться, что это и есть пароль. Так что нужно придумывать что-то другое.

Очевидно, эталон пароля, который хранится в зашифрованном файле, тоже надо зашифровать. Только как? Проще всего шифровать пароль по той же схеме, что и текст исходного файла. Если шифр стойкий (а иначе его и не стоит использовать), пароль будет закрыт надежно. А что брать в качестве ключа? Можно взять константу. Тогда в каждом зашифрованном файле эталон пароля будет зашифрован на одном и том же ключе. Так, например, делает встроенная система шифрования файлов электронной почты Sprint Mail. Только там зашифрованный пароль хранится не в начале зашифрованного файла, а в конце. Но что будет, если кто-то узнает ключ, на котором шифруются все пароли? Он сможет расшифровывать все файлы, которые вы зашифруете. И не важно, что пароли разные — злоумышленник возьмет нужный пароль прямо из файла, который хочет прочесть.

Вы, скорее всего, подумали: а откуда злоумышленник узнает ключ, на котором шифруются эталоны паролей? Этот ключ встроен в программу шифрования, его никто не знает, даже вы его не знаете. Тем не менее, если злоумышленник достаточно квалифицирован, если он умеет пользоваться дизассемблером и отладчиком, этот ключ он узнает без труда. Обычно на решение такой задачи уходит всего несколько часов. Как это можно сделать — тема отдельной статьи. Пока поверьте на слово — имея только ехе-файл, определенные навыки и много свободного времени, можно разобраться в том, что делает программа, до мельчайших подробностей.

Лучше шифровать эталон пароля сам на себе. Взять пароль в качестве открытого текста и взять тот же пароль в качестве ключа. При расшифровании файла, когда вы вводите пароль, программа пытается расшифровать только начало файла. Если в результате получилась строка, совпадающая с паролем, значит, пароль правильный, и можно расшифровывать файл дальше. А если получилось что-то другое, значит, пароль неправильный.

Некоторые программы шифрования шифруют пароли иначе. Берется какая-то строка, всегда одна и та же, шифруется на пароле и записывается в зашифрованный файл. Diskreet, например, шифрует на пароле строку «ABCDEFGHENRIXYZ» (эта строка завершается нулевым байтом, как принято в языке С). Когда Diskreet проверяет пароль, он берет начало зашифрованного файла (точнее, байты с 16-го по 31-й) и расшифровывает их на пароле, который ввел пользователь. Если после

расшифрования получилось «ABCDEFGHENRIXYZ» - пароль правильный, если не получилось — неправильный.

На первый взгляд кажется, что эта схема хуже, чем предыдущая. Действительно, в предыдущем случае злоумышленнику неизвестны ни открытый текст, ни ключ, а в последнем случае неизвестен только ключ, а открытый текст известен. Но если вы еще помните, что было написано в начале этой главы, то, наверное, уже поняли, что последняя схема ничуть не слабее предыдущей. Если шифр стойкий, то ключ шифрования невозможно получить за приемлемое время, даже если известны и открытый текст, и шифртекст.

Какой должен быть пароль?

Какой длины должен быть пароль, чтобы защита была стойкой? Число различных вариантов пароля должно быть не меньше числа различных ключей. Если вы шифруете файл с помощью алгоритма ГОСТ, а для пароля используете только строчные английские буквы и хотите, чтобы стойкость защиты была не ниже стойкости ГОСТа, то длина пароля должна быть не меньше, чем (Здесь 2256 — число различных ключей число различных английских букв.) Так что вам придется придумывать -буквенный пароль. К тому же учтите, что если вы используете в качестве пароля не хаотичную последовательность букв, а осмысленную фразу, то нужно сделать поправку на избыточность языка. Если в пароль входят не только строчные буквы, но и заглавные, то для обеспечения необходимого числа ключей ГОСТ достаточно 51 символа. Только имейте в виду, что некоторые программы шифрования, получив пароль, преобразуют все его буквы к одному регистру. Например, Diskreet делает все английские буквы, входящие в пароль, заглавными. Вы можете использовать в пароле русские буквы, но будьте осторожны! Не все программы шифрования корректно работают с русскими паролями. Таблица 1 поможет вам оценить требуемую длину пароля в различных ситуациях.

Имейте в виду, что данные в этой таблице относятся к тому случаю, когда в качестве пароля берется равномерно распределенная случайная последовательность символов. Если в качестве пароля вы используете только осмысленные слова и фразы, количество возможных вариантов пароля будет гораздо меньше. Если в качестве пароля используется длинная фраза русского языка, то, как показывают теоретико-информационные исследования, количество возможных вариантов будет равно не где число символов во фразе, а всего лишь (эта приближенная оценка верна только для больших Так что в этом случае для достижения стойкости DES придется брать пароль длиной 56 символов, а для достижения стойкости символов.

(см. скан)

Так стоит ли вообще использовать для шифрования пароль, вводимый с клавиатуры? Для ответа на этот вопрос надо определить для себя — от кого вы собираетесь защищать информацию. Если ваш противник умеет только подбирать пароль с клавиатуры, то в качестве пароля лучше всего взять осмысленное слово длиной 6-8 символов. Главное, чтобы злоумышленнику было трудно догадаться до этого слова. При этом надо помнить, что нельзя использовать в качестве пароля:

- свое имя (фамилию, отчество, прозвище,

- свою дату рождения (номер телефона, номер паспорта,

- имя того файла, который вам надо зашифровать;

- и все другие пароли, которые легко угадать.

Если ваш противник, от которого вы защищаете информацию, умеет программировать, то он может написать программу, которая будет подбирать пароль автоматически. Даже если противник не умеет программировать, он может взять такую программу из Internet - там таких программ много. В этом случае пароль не должен быть осмысленным словом. В современном английском языке обычно употребляется всего около 100000 слов, в русском — чуть больше. Перебрать 100000 паролей можно очень быстро. Если в качестве шифра используется DES, на процессоре Pentium можно перебрать все английские слова-пароли всего за несколько секунд.

Даже если пароль представляет собой слово, которого нет в словаре, его все равно можно легко угадать. Вы уже знаете, что порядок букв в словах и фразах естественного языка подчиняется определенным статистическим закономерностям. Например, в русском языке комбинация букв встречается часто, а никогда. Для большинства естественных языков статистика встречаемости символов документирована. Если программа перебора вначале подбирает наиболее вероятные пароли, а менее вероятные оставляет на потом, то перебор сокращается в десятки и сотни раз. Один из авторов видел, как подобная программа подобрала пароль natenok на компьютере с процессором 386DX-40 всего за 10 минут. Общая сложность перебора была равна Вот другие известные авторам случаи удачного подбора паролей:

(см. скан)

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

другое — пятибуквенным. Во втором случае пароль состоял из трех строчных английских букв, двух заглавных английских букв и одной цифры. Этот пароль был абсолютно бессмысленным. Выводы делайте сами.

Лучший результат по подбору ключа был достигнут в 1997 году, когда в сети Internet был дешифрован файл, зашифрованный с помощью DES. В подборе ключа участвовали десятки тысяч пользователей Internet. Все множество ключей было разбито на непересекающиеся подмножества и каждый перебирал ключи из своего подмножества. Перебор длился несколько недель. Руководил работой добровольной «виртуальной» бригады взломщиков со своего сервера программист Рокки Версер — автор программы, перебирающей ключи. Общая сложность перебора составляла но ключ был найден после перебора всего 25% ключей. При этом «расколол» сообщение компьютер с процессором Pentium/90 с 16 Мбайт оперативной памяти. Оно гласило: «Надежная криптография делает мир безопасным».

А можно ли обойтись без пароля?

Как видите, применять пароль в качестве ключа шифрования не так удобно, как кажется на первый взгляд. Либо защита будет нестойкой, либо пароль трудно запомнить и ввести без ошибок. Если вы хотите построить по-настоящему надежную защиту, вместо пароля нужно использовать что-то другое.

Можно, например, хранить ключ на дискете. Вы создаете каким-то образом (каким — обсудим позже) случайный, равновероятный и достаточно длинный ключ и записываете его на дискету. Когда программа шифрования запрашивает ключ, вы вводите ключ не с клавиатуры, а с дискеты. Вы просто вставляете дискету в дисковод, а программа считывает оттуда ключ и зашифровывает файл на этом ключе. При расшифровании файла программа просит «Вставьте ключевую дискету в дисковод». Вы вставляете дискету в дисковод, программа считывает оттуда ключ, проверяет его правильность и, если ключ правильный, расшифровывает файл.

Конечно, программа шифрования должна уметь работать с ключевыми дискетами.

Ключевую дискету нужно хранить в месте, недоступном для злоумышленников. Если кто-то воспользуется вашей ключевой дискетой, то он сможет прочесть все, что вы зашифровали с ее помощью. Не теряйте ключевые дискеты! Если вы потеряете такую дискету, то тем

самым вы потеряете все данные, которые вы зашифровали с ее помощью.

Удобно ли пользоваться ключевыми дискетами? Нет. Но за надежность защиты приходится платить. Вообще, это общая закономерность — чем надежнее система защиты, тем труднее с ней работать. И наоборот, чем система защиты удобнее в обращении, тем она слабее. Конечно, разрабатывая систему защиты, можно наделать ошибок, и система получится и ненадежной, и неудобной. Но если система разрабатывалась на совесть, приведенное выше утверждение почти всегда верно.

Можно ли как-нибудь защитить ключ, хранящийся на дискете? Конечно! Его тоже можно зашифровать. И не нужно для этого придумывать сложный шифр — вполне хватит самого примитивного шифра наподобие простой замены. Почему? Да потому, что ключ шифрования — текст случайный и равновероятный. На чем основан метод дешифрования шифра простой замены? На том, что открытый текст — это осмысленный текст. А в осмысленном тексте обязательно присутствуют статистические закономерности. Но в ключе никаких закономерностей нет — ключ случаен и равновероятен!

Что использовать в качестве ключа, на котором шифруется ключ? Можно использовать пароль, но, как вы уже знаете, это не очень надежно. Можно завести вторую ключевую дискету, на которой хранить ключ, необходимый для доступа к первой. Но тогда придется заводить третью дискету, чтобы защитить вторую, а потом заводить четвертую, чтобы защитить третью ...

Так как же быть? Подумайте сами. Один из возможных ответов вы найдете в конце главы.

Где взять ключи?

Каким должен быть ключ шифрования? Случайным и равновероятным. А как получить случайную и равновероятную последовательность символов? Правильно, с помощью генератора случайных чисел. Написать свой генератор «случайных» чисел очень просто. Хорошие по статистическим свойствам последовательности получаются по формуле линейного конгруэнтного метода:

где член псевдослучайной последовательности; некоторые целые числа.

Качество псевдослучайной последовательности зависит от выбора чисел Эти числа обязательно должны быть взаимно просты. Есть и другие правила выбора этих коэффициентов, о них можно прочитать в [1]. В Diskreet, например, используется следующий генератор

псевдослучайной последовательности:

Как видите, формула для получения очередного «случайного» числа рекурсивна — каждый член последовательности зависит от предыдущего. Возникает вопрос: откуда берется первый член? Обычно в качестве берут текущее время с точностью до тика таймера (0,054945 сек.). Если для генерации ключа используется линейный конгруэнтный метод, ключом является последовательность чисел где

Предположим, что с помощью линейного конгруэнтного метода сгенерирована последовательность каждое есть короткое целое число (16 бит). Созданный ключ представляет собой случайную равновероятную последовательность длиной 256 байт. Оценим, сколько различных вариантов ключа можно получить по данной схеме.

Зафиксируем значение Какие значения может принимать Только одно значение. Если фиксировано, то значение определено однозначно:

Значение тоже определено однозначно. Оно равно

Таким образом, значение однозначно определяет значения всех следующих членов последовательности. Получается, что различных последовательностей в точности столько же, сколько различных значений . В нашем примере короткое целое число, принимающее значения от 0 до Оказывается, что стойкость ключевой системы (число различных вариантов ключа) равна не 2256, а всего лишь 216, что в раз меньше!

Получается, что псевдослучайные последовательности в качестве ключей использовать нельзя. А что можно?

В чем слабость псевдослучайных последовательностей? В том, что они псевдослучайны. Первый член последовательности однозначно определяет остальные. Чтобы ключ был по-настоящему случайным и равновероятным, последовательность должна быть не псевдослучайной, а истинно случайной.

Где взять истинно случайную последовательность?

На первый взгляд, эта задача очень проста. Можно, например, вычислить случайный адрес памяти и взять оттуда данные. Или можно вычислить случайный номер сектора на диске и взять данные оттуда.

Эти данные, бесспорно, будут случайными. Но какое распределение будут иметь члены полученной случайной последовательности? Неизвестно. Если полученные случайные данные представляют собой фрагмент текстового файла, то распределение символов, представляемых байтами файла, будет одно, если это фрагмент машинного кода — совсем другое. Одно можно сказать точно — это распределение почти никогда не будет равномерным. Ниже приведены гистограммы встречаемости символов для различных видов информации.

(см. скан)

Как видите, из всех приведенных гистограмм только последняя более менее похожа на гистограмму равномерного распределения. Однако, если приглядеться повнимательнее, в ней можно заметить пик вдоль оси Y (впрочем, этот пик нетипичен для архивов он объясняется тем, что выбранный архив включал в себя очень много коротких файлов).

Конечно, если распределение исходной последовательности задано априорно, путем несложного преобразования эту последовательность можно превратить в распределенную равномерно. Но подсчитать распределение символов для информации, хранимой в памяти и на дисках компьютера, не удается даже в том случае, если известно, откуда эта информация взялась. Посмотрите на гистограмму встречаемости символов в тексте этой главы. А теперь посмотрите на следующую гистограмму.

(см. скан)

Как видите, распределения отличаются довольно сильно. Получается, что если в документе есть картинки, исходное распределение одно, а если нет — совсем другое.

Кроме того, в осмысленных текстах (в том числе и в текстах ехе-файлов, баз данных и т. д.) обязательно присутствуют статистические закономерности более высокого порядка. Если построить гистограмму встречаемости биграмм и триграмм, она будет еще менее похожа на горизонтальную линию (что должно иметь место при равномерном распределении), чем гистограмма встречаемости отдельных символов. Например, в ехе-файле, скомпилированном с помощью Visual С++, машинный код подавляющего большинства функций (подпрограмм) начинается байтами

и заканчивается байтами

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

Так где же взять случайную последовательность?

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

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

Случайная? Несомненно. Равномерно распределенная? Вряд ли. Какое у нее будет распределение? Трудно сказать. Если пользователь набирает текст, получится одно распределение, если работает с Norton Commander - другое, если играет в Tetris - третье. Будут ли соседние элементы последовательности зависеть друг от друга? Скорее всего, да.

Кажется, что никаких преимуществ по сравнению с предыдущим методом нет. Однако в отличие от предыдущего метода в данном случае все перечисленные проблемы можно решить.

Для начала посмотрим, можно ли написать программу генерации ключа так, чтобы распределение исходной случайной величины было известно. Исходная случайная величина у нас — это продолжительность интервала между нажатиями клавиш. В разных ситуациях эта величина распределена по-разному. Выберем ситуацию, когда распределение этой случайной величины легко посчитать. Пусть, например, пользователь в процессе выработки ключа играет в Tetris. При игре в Tetris частота нажатий на клавиши мало зависит от пользователя, другими словами, все пользователи, играя в Tetris, нажимают на клавиши примерно одинаково часто (конечно, кроме пользователей, которые играют в Tetris первый раз в жизни).

Распределение интервалов времени между последовательными нажатиями на клавиши несложно рассчитать. Для этого нужно прежде всего написать резидентную программу, которая перехватывала бы прерывание 16h, отвечающее за работу с клавиатурой, при каждом вызове прерывания получала бы текущее значение таймера, сравнивала его с предыдущим полученным значением, вычисляла разность и записывала полученное число в файл. Затем нужно запустить эту программу и, пока она работает, поиграть некоторое время в Tetris. Проведите этот эксперимент в качестве упражнения.

Посмотрите на рисунок. Распределение нашей случайной величины будет выглядеть примерно так:

(см. скан)

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

(см. скан)

Остается решить последнюю проблему. Таймер компьютера тикает с частотой 18,2 раза в секунду, т. е. один тик занимает примерно 55 миллисекунд. Когда пользователь нажимает клавиши подряд, не думая, или просто держит клавишу нажатой, интервалы между последовательными нажатиями составляют 100-200 миллисекунд. Получается, что первый пик на приведенном графике на самом деле выглядит примерно так, как показано на рисунке.

А это нехорошо — в полученной случайной последовательности числа 2 и 3 будут встречаться гораздо чаще, чем любые другие. После преобразования к равномерному распределению значения этих часто встречающихся чисел изменятся, но сам факт наличия двух-трех значений, на которые приходится львиная доля наблюдений, останется.

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

<< Предыдущий параграф Следующий параграф >>
Оглавление