Ars Longa, Vita Brevis

Почему нужно изучать криптографическую библиотеку перед ее использованием

Разбираясь с деталями реализации распределителей памяти (allocator) в C++, я решил вспомнить своё криптографическое прошлое :-) Не в том плане, что я эксперт в криптографии, а в том, что приходилось читать соответствующую литературу (до сих порэтот гигабайт на винте валяется), разбираться с ней, анализировать алгоритмы, оценивать их с точки зрения безопасности и в том же духе. Но это не важно. Разбираясь с деталями реализации, я вспомнил интересную статью Питера Гутмана, "Secure Deletion of Data from Magnetic and Solid-State Memory". Еще в то время, когда я этим всем активно занимался и читал, мне в голову прочно врезалась фраза, смысл которой сводился к тому, что очень немногие криптографические библиотеки действительно заботятся о конфиденциальности чувствительной информации (например, ключи шифрования). Ведь информацию можно "вытащить" и из памяти выключенного компьютера; или с жесткого диска, даже если информация была переписана. Всех, кому интересна практическая реализация восстановления информации, отсылаю к статье Питера Гутмана (ссылка приведена выше).

Итак, сегодня выдалось очень подходящее настроение для копания в чужом C++ коде. Вот что из этого получилось.

Я рассмотрел две библиотеки: BeeCrypt и Crypto++ 5.5.2.

Сразу оговорюсь, что специалисты по безопасности — настоящие параноики, поэтому они способны предполагать такие вещи. которые нормальному человеку и в голову не придут, поэтому даже если некоторые приводимые предположения кажутся высосанными из пальца, то к ним всё равно стоит относиться очень серьёзно :-).

Итак, почему необходимо надёжно удалять чувствительную информацию? Очевидно, потому что существуют способы её восстановления. Предположим "невозможную" ситуацию: сидел человек, никого не трогал, шифровал документы, представляющие собой государственную тайну. Может, он был шпионом, может, еще кем-нибудь. Не важно. Тут врываются представители закона/ОМОН/контрразведка (нужное подчеркнуть). Документы уже зашифрованы, оригинала нет, доказать, что-либо представляется очень трудным (да, шифры бывают разными; на дешифрирование может уйти несколько тысяч лет). Что делать? Терморектальный криптоанализ не в счет :-) В этом случае спецы могут конфисковать оперативную память и жесткий диск, специальными методами снять с их информацию. Благо, технология позволяет. Можно попробовать поискать в памяти ключ шифрования. Можно поискать его в свопе. И велика вероятность, что его можно найти. Лирическое отступление: я вспомнил одного своего универского препода, который говорил, что спецы могут вытащить информацию с диска, который побывал в кислоте. Правда или нет, я не знаю. Но вероятность есть.

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

Я для себя сделал такой вывод: чувствительная информация (те же ключи) никогда не должна попадать на диск. Для этого есть свои причины: во-первых, если системе начинает нехватать памяти, она начинает своппинг. В своп могут попасть эти самые чувствительные данные. Причем там они будут храниться в открытом виде и при желании их всегда можно достать :-) Во-вторых, пользовательскому процессу очень трудно перетереть даже свои данные в свопе (а если это еще делать в соответствии с таблицей, приведенной в статье Гуттмана…). В-третьих, нет гарантии, что запись не будет кэшироваться. Кэшировать может что угодно: библиотека ввода-вывода, операционная система, драйвер ввода-вывода, контроллер диска. Следовательно, у нас нет гарантии, что если мы выполним перезапись 35 раз, то жанные будут перезаписаны 35 раз. особенно, если программа не обладает привелегиями суперпользователя.

Таким образом, при выделении памяти для чувствительной информации необходимо позаботиться о том, чтобы выделенная память не попала на диск. В Windows для этого можно использовать VirtualLock() или AWE. В Linux — mlock(). Опять же, цитируя Гутмана, в Windows это должно сработать:

I had a long discussion about this with some MS technical people and it appears that (at least in Win2K and newer) VirtualLock is more effective than expected. One of the MS guys tried everything possible to get VirtualLocked'd memory paged and couldn't get it swapped out. Unfortunately the info for different Windows versions and at different times has been conflicting, but it appears that with newer versions of Windows it has at least some positive effect.

Что мы видим в вышеуказанных библиотеках? Память выделяется либо при помощи new (BeeCrypt), либо через allocator (malloc()/free(); Crypto++). Ни один из данных способов не гарантирует, что выделенная память не отправится в своп. Отвлекаясь от темы, тем, к�