Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Практическая криптография

..pdf
Скачиваний:
6
Добавлен:
12.11.2023
Размер:
16.23 Mб
Скачать

162

Глава 9. Проблемы реализации. Часть I

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

Как же помешать системе виртуальной памяти записывать наши данные на диск? В некоторых операционных системах есть специальные системные вызовы. С их помощью можно уведомить систему виртуальной памяти о том, что содержимое указанных областей памяти не должно подвергаться переме­ щению в файл подкачки. Иногда (хотя, к сожалению, крайне редко) нам всетаки попадаются операционные системы, которые поддерживают безопасную подкачку. В этом случае данные, перемещаемые в файл подкачки, подверга­ ются криптографической защите. Если ваша операционная система не обла­ дает ни одной из этих возможностей, считайте, что вам не повезло. Громко пожалуйтесь на нее окружающим и сделайте все, что в ваших силах.

Предположим, вы можете заблокировать память и предотвратить пере­ мещение ее содержимого в файл подкачки. Но какую же память следует блокировать? Разумеется, всю ту память, в которой могут храниться наши секретные данные. Тут возникает еще одна проблема. Во многих средах про­ граммирования практически невозможно определить, где именно хранятся те или иные данные. Объекты часто содержатся в “куче”, константы — в стати­ ческой памяти, а большинство локальных переменных оказываются в стеке. Определить более точное расположение данных при этом может быть затруд­ нительно, да и не исключено появление ошибок. Вероятно, более удачным ре­ шением будет блокирование всей памяти, занятой приложением. Конечно же, это не так просто, как кажется на первый взгляд, поскольку может привести к потере целого ряда служб операционной системы, таких, как автоматиче­ ски выделяемый стек. Кроме того, блокирование всей памяти приложения делает систему виртуальной памяти неэффективной.

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

9.3.3Кэш

Современные компьютеры не ограничены каким-то одним типом памя­ ти. Они обладают целой иерархией типов. В самом низу иерархии находится*

ХВ действительности никогда не следует записывать секретные данные на какой-либо постоянный носитель, предварительно не зашифровав их, но об этом мы поговорим позже.

9.3 Как сохранить секреты

163

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

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

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

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

164

Глава 9. Проблемы реализации. Часть I

9.3.4Удерживание данных в памяти

Очень многих удивляет тот факт, что простое перезаписывание данных не обязательно приводит к их удалению. Детали этого процесса в некоторой степени зависят от типа используемой памяти, однако в общем случае, если данные помещаются в какую-либо область памяти, эта область начинает по­ тихоньку “заучивать” или “удерживать” данные. Когда вы перезаписываете данные или выключаете компьютер, старые данные теряются не полностью. В зависимости от обстоятельств, простое выключение и включение питания может восстановить некоторые или все старые данные. Другие типы памяти могут “вспомнить” старые данные, если доступ к ним осуществляется в те­ стовых режимах (часто незадокументированных) [38].

Причина этого феномена кроется в принципах работы нескольких меха­ низмов. Если одни и те же данные на протяжении достаточно долгого вре­ мени хранятся в одной и той же области статической оперативной памяти (Static RAM — SRAM), они будут рассматриваться как предпочтительное со­ стояние загрузки этой памяти. Наш друг столкнулся с этой проблемой мно­ го лет назад при сборке компьютера в домашних условиях [9]. Он написал BIOS, которая использовала магическое число (magic value), расположенное в конкретной области памяти, чтобы определить, какая выполняется переза­ грузка: “холодная” (cold reboot) или “горячая” (warm reboot)2. Через некото­ рое время машина отказалась загружаться после выключения и повторного включения компьютера, потому что оперативная память “выучила” магиче­ ское число, в результате чего каждая перезагрузка воспринималась системой как горячая. Поскольку в процессе горячей перезагрузки не инициализиро­ вались некоторые нужные переменные, система не могла загрузиться. Для устранения этой проблемы пришлось поменять местами некоторые модули памяти, чтобы SRAM не могла “вспомнить” магическое число, которое она “выучила”. Для нас это послужило уроком: оперативная память сохраняет больше данных, чем мы думаем.

Аналогичные, хотя и несколько более сложные процессы происходят с ди­ намической оперативной памятью (Dynamic RAM — DRAM). Кодирование битов в памяти DRAM выполняется путем помещения небольшого электри­ ческого заряда в крошечный конденсатор. Изоляционный материал вокруг пластин конденсатора подвергается напряжению, что приводит к измене-

2В те времена компьютеры, собранные в домашних условиях, программировались путем непосредственного введения двоичной формы машинного языка, что, конечно же, приводи­ ло к появлению массы ошибок. Один из гарантированных способов восстановить машину после “падения” программы заключался в перезагрузке компьютера. Холодная перезагруз­ ка — это выключение и повторное включение компьютера. Горячая перезагрузка — это пе­ резагрузка наподобие той, что выполняется при нажатии кнопки Reset. В процессе горячей перезагрузки система не выполняет повторную инициализацию всего состояния, а значит, не уничтожает настройки, сделанные пользователем.

9.3 Как сохранить секреты

165

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

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

Пока что нами придумано лишь частичное решение этой проблемы, кото­ рое срабатывает только при наличии определенных (и достаточно разумных) предположений об оперативной памяти. Это решение, которое мы назвали Boojum3, подходит для сравнительно небольших объемов данных, таких, как ключи. Пусть т — это данные, которые нужно сохранить в оперативной па­ мяти. Вместо того чтобы сохранять т , мы генерируем случайную строку R и сохраняем значения R и R ® т. Эти значения сохраняются в различных областях памяти, по возможности расположенных не слишком близко друг от друга. Хитрость состоит в том, чтобы регулярно изменять значение R. Че­ рез одинаковые промежутки времени (скажем, 100 мс) мы генерируем новое случайное значение R' и обновляем содержимое памяти, сохраняя значения й ф Rf и й ® Д 'ф т . Это гарантирует, что поверх каждого бита памяти будет перезаписана случайная последовательность битов. Чтобы очистить память, мы просто создаем новое т , значение которого равно нулю. В результате этого в обеих областях памяти окажутся два равных случайных значения.

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

Необходимо тщательно следить за тем, чтобы биты значений R и йфтп не оказались смежными на микросхеме памяти. Если не известно, как функци­ онирует микросхема памяти, это может быть непростой задачей. В большин­ стве типов памяти, однако, биты данных хранятся в узлах прямоугольной решетки, причем одни биты адреса области памяти указывают на строку, а другие — на столбец. Если адреса двух элементов данных различаются на 0x5555, тогда с очень высокой долей вероятности эти данные не являются смежными. (Разумеется, это предполагает, что микросхема памяти не исполь­ зует четные биты адреса в качестве номера строки, а нечетные — в качестве

3По имени Буджума — героя кииги Льюиса Кэрролла “Охота на снарка" [15].

166 Глава 9. Проблемы реализации. Часть I

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

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

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

До сих пор, описывая Boojum, мы говорили только о главной памяти. Это же решение применимо и к кэш-памяти за исключением того, что вы не сможете контролировать, в каком узле микросхемы будут храниться данные. К сожалению, Boojum не подходит для регистров процессора, однако они применяются так часто для хранения огромного количества самой разной информации, что возникновение эффекта удержания весьма маловероятно. С другой стороны, регистры расширения, такие, как регистры с плавающей запятой или дополнительные регистры ММХ, используются гораздо реже, а значит, представляют собой потенциальную проблему.

Если у вас есть большие объемы данных, которые нужно сохранить в сек­ рете, тогда сохранение в оперативной памяти двух значений и регулярное прибавление к ним новых случайных строк может оказаться слишком дорого­ стоящим решением. В этом случае предпочтительнее зашифровать большой блок данных и сохранить в памяти шифрованный текст. Избежать “удержа­ ния” должен только ключ, для сохранения которого можно воспользоваться алгоритмом Boojum. Более подробно это рассматривается в статье [23].

9.3.5Доступ других программ

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

9.3 Как сохранить секреты

167

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

Огромную опасность в этом отношении представляют программы-отлад­ чики. Современные операционные системы часто содержат средства, предна­ значенные для использования отладчиками. Различные версии Windows поз­ воляют подключить отладчик к уже запущенному процессу. Отладчику раз­ решено делать многое, в том числе и читать память. Кроме того, в UNIX ино­ гда возможно создать дамп оперативной памяти для конкретной программы. Дамп оперативной памяти (core dump) — это файл, содержащий образ памя­ ти, в которой хранятся данные программы, включая и все секретные данные.

Еще одна угроза исходит от особо могущественных пользователей. Такие люди, называемые суперпользователями (superusers) или администратора­ ми (administrators)> могут осуществлять доступ к содержимому компьютера, недоступному для обычных пользователей. Например, в операционной систе­ ме UNIX суперпользователь может читать любую часть памяти.

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

9.3.6Целостность данных

Помимо сохранения секретов, мы должны защищать и целостность дан­ ных. Для защиты целостности данных в процессе их передачи по каналу общения используется код аутентичности сообщения (MAC), но как же быть, если данные будут изменены в памяти компьютера?

В этой главе мы предполагаем, что аппаратное обеспечение является на­ дежным. Если оно ненадежно, вам вряд ли удастся сделать что-нибудь сто­ ящее. Если вы не уверены в надежности своего оборудования, потратьте немного времени и памяти на то, чтобы это проверить, хотя в действитель­ ности такой работой должна заниматься операционная система. Лично мы всегда стараемся гарантировать, что главная память компьютера поддержи­ вает технологию кода коррекции ошибок (error correcting code — ЕСС)4. Если в каком-нибудь одном разряде памяти произойдет ошибка, ЕСС обнаружит и исправит ее. При отсутствии ЕСС ошибка в любом разряде приведет к тому, что процессор считает неправильные данные.

4Убедитесь, что все компоненты компьютера поддерживают ЕСС. Остерегайтесь более дешевых модулей памяти, которые не сохраняют дополнительную информацию, а пере­ считывают ее “па лету”. Это сводит на нет само назначение ЕСС.

168 Глава 9. Проблемы реализации. Часть I

Почему это так важно? Память современных компьютеров содержит ги­ гантское количество разрядов. Предположим, что модули памяти облада­ ют высоким качеством сборки, а значит, вероятность сбоя каждого разряда в конкретную секунду времени составляет только 10” 15. Если в компьютере установлены 128 Мбайт памяти, у нас есть около 109 разрядов, а следователь­ но, сбоя одного разряда можно ожидать каждые 11 дней, что, разумеется, не слишком хорошо для наших систем. Частота ошибок возрастает с увеличени­ ем объема памяти, поэтому в компьютере с 1 Гбайт памяти появления ошибки можно ожидать каждые 32 часа. Серверы обычно используют память с под­ держкой ЕСС, поскольку обладают большим количеством памяти и вынуж­ дены беспрерывно работать на протяжении длительных периодов времени. Хотелось бы, чтобы подобной стабильностью обладали и все другие машины.

Разумеется, данная проблема касается исключительно аппаратного обес­ печения. В большинстве случаев вы не сможете проконтролировать тип па­ мяти компьютера, на котором будет запущена готовая система.

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

9.3.7 Что делать

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

Помимо всего прочего, описанные проблемы значительно затрудняют со­ здание библиотеки криптографических функций. Сохранение данных в сек­ рете часто требует внесения изменений в главную программу. И разумеется, главная программа также работает с данными, которые должны быть сохра­ нены в секрете; в противном случае ей бы вообще не понадобилась криптогра­ фическая библиотека. Это одна из распространенных проблем безопасности, которая влияет на все части системы.

9.4 Качество кода

169

 

9.4Качество кода

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

9.4.1Простота

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

В качестве типичного примера простой системы можно привести наш без­ опасный канал общения. У него нет настроек. Он не позволяет зашифровать данные без аутентификации или применить аутентификацию без шифрова­ ния. Многие клиенты просят реализовать подобные возможности, но в боль­ шинстве случаев они просто не представляют себе последствий частичного использования средств безопасности. Многие пользователи знают о безопас­ ности отнюдь не достаточно, чтобы самостоятельно выбирать правильные параметры безопасности. Лучшее, что можно предложить в подобной ситу­ ации, — это вообще лишить систему настраиваемых параметров и сделать ее безопасной по умолчанию. Если же без настроек все-таки не обойтись, оставьте один параметр — безопасная или небезопасная.

Многие криптографические системы также оснащены несколькими паке­ тами шифров. В таких системах пользователь (или кто-нибудь другой) мо­ жет самостоятельно выбирать шифр и функцию аутентификации. На наш взгляд, этого делать не рекомендуется. Оставьте один режим, который будет достаточно безопасным для всех возможных областей применения. Разница

вобъеме вычислений для разных режимов шифрования не так уж велика,

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

170

Глава 9. Проблемы реализации. Часть I

9.4.2Модуляризация

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

Безусловно, вы уже не раз встречались с модуляризацией. В криптогра­ фии же правильная разбивка на модули играет еще более важную роль. Ранее мы уже рассматривали криптографические объекты и функции в качестве от­ дельных модулей. Интерфейс модуля должен быть простым и понятным. Его поведение должно соответствовать разумным ожиданиям пользователя это­ го модуля. Приглядитесь к интерфейсам своих модулей. Зачастую они вклю­ чают в себя средства или настройки, предназначенные для решения задач какого-нибудь другого модуля. Если это возможно, выбросите такие сред­ ства. Каждый модуль должен заниматься только собственными проблемами. По своему опыту мы знаем, что наличие в интерфейсе модуля “странных” средств практически всегда является результатом неадекватного проектиро­ вания. Такое программное обеспечение определенно требует переделки.

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

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

9.4. Качество кода

171

реакторе? Или о парашютисте, который одевает запасной парашют на тре­ нировках, но снимает его, когда выпрыгивает из самолета? Зачем кому-то вообще понадобилось отключать проверку утверждений в готовом продук­ те — ведь это, по сути, единственное место, где она нужна? Если в процессе функционирования реальной системы произойдет нарушение утверждения, мы всего-навсего получим ошибку программирования. Игнорирование ошиб­ ки, в свою очередь, может привести (и, скорее всего, приведет) к выдаче неверного ответа, потому что по крайней мере одно предположение, сделан­ ное кодом, будет неправильным. Выдача неверных ответов — это, пожалуй, худшее, что может сделать программа. Гораздо лучше проинформировать пользователя о возникновении ошибки программирования, чтобы он не дове­ рял ошибочным результатам, выданным программой. Никогда не отключайте проверку ошибок!

9.4.4Переполнение буфера

Современной IT-иидустрии должно быть стыдно за появление в нашей книге раздела с таким заголовком. Проблемы переполнения буферов пресле­ дуют нас на протяжении уже 40 лет. Все это время в мире существовали и решения для борьбы с ними. Некоторые из ранних языков программиро­ вания высокого уровня, например Algol 60, полностью решали эту проблему путем введения обязательной проверки границ массива. К сожалению, даже несмотря на наличие массы поистине замечательных решений, переполнение буферов до сих пор является причиной более половины всех проблем безопас­ ности, возникающих в Internet. Устранять же эти проблемы никто не собира­ ется. Мы считаем это преступной халатностью. Что бы мы подумали, если бы производитель автомобилей сделал бензобак из оберточной бумаги? Конечно же, при определенной доле везения машина могла бы прекрасно ездить и с та­ ким бензобаком, но руководство компании-производителя все равно угодило бы за решетку. Между тем целые отрасли IT-индустрии ведут себя так, буд­ то не являются ответственными за последствия своих действий. (Возможно, наши юристы разрешают им свободно отказываться от своих обязательств, что было бы неприемлемо в любой другой области.) Наблюдая подобное от­ ношение к программному обеспечению, мы часто задумываемся: а стоит ли вообще пытаться внедрять что-нибудь такое сложное, как криптография?

К сожалению, мы не в состоянии изменить текущее положение дел. Мы можем лишь посоветовать вам, как написать хороший криптографический код. Откажитесь от языков программирования, которые допускают перепол­ нение буфера. В частности, не используйте С или C++. И никогда не от­ ключайте проверку границ массива, какой бы язык вы не использовали. Это,