«Розрубати Гордіїв вузол» або подолання проблем шифрування інформації в ОС Windows

Сучасна операційна система-це складний иерархичный процес обробки і управління інформацією. Актуальні версії ОС Windows в цьому питанні не є виключенням. Для того, щоб інтегрувати засіб захисту в середовище ОС Windows, часто вистачає вбудовування на прикладному рівні. Однак, якщо мова заходить про шифрування інформації в середовищі ОС Windows, все стає набагато складніше.

Основний «головним болем» розробника засобів шифрування в цьому процесі є забезпечення «прозорості шифрування», тобто необхідно гармонійно вбудуватися в структуру процесів операційної системи і при цьому забезпечити незалучення користувачів в процес шифрування і вже тим більше його обслуговування. Вимоги до сучасних засобів захисту все більше і більше виключають користувача з процесу захисту інформації. Таким чином, для цього самого користувача створюються комфортні умови, які не потребують прийняття «незрозумілих» рішень щодо захисту інформації.
У даній статті будуть розкриті ідеї ефективної інтеграції засоби шифрування інформації на диску з процесами файлової системи ОС Windows.
Перед розробниками ставилася мета створити механізм шифрування інформації на диску, відповідає вимогам максимальної прозорості для користувачів. Вимоги повинні будуть виконуватися за рахунок ефективної взаємодії цього механізму шифрування з процесами операційної системи Windows, які відповідають за управління файловою системою. Ефективність механізму шифрування повинна також підтверджуватися високою продуктивністю процесів шифрування і раціональним використанням ресурсів операційної системи.
Спочатку була поставлена задача надавати одночасний доступ до зашифрованого і расшифрованному вмісту, а також зашифрувати імена файлів. Це і породжує основні складності, оскільки така вимога йде в розріз зі сформованою архітектурою Windows. Щоб зрозуміти суть проблеми, для початку нам слід розібрати деякі основні моменти даної операційної системи.
У Windows всі файлові системи покладаються на такі підсистеми, як менеджер пам'яті і кеш менеджер, а менеджер пам'яті, в свою чергу, покладається на файлові системи. Здавалося б, замкнуте коло, але все стане зрозуміло далі. Нижче, на рисунку 1, зображені перераховані компоненти, а також менеджер вводу/виводу, який приймає запити від підсистем (наприклад Win32) і від інших драйверів системи. Також на малюнку використовуються терміни «фільтр» та «стек файлової системи», про що докладніше буде розказано нижче.

Малюнок 1


Розберемо такий механізм, як відображення файлу на пам'ять. Суть його полягає в тому, що при доступ до віртуальної пам'яті в реальності читається частину файлу. Реалізується це за допомогою апаратних механізмів процесорів і безпосередньо самого менеджера пам'яті. Будь-які діапазони віртуальної пам'яті процесу описуються дескрипторами. Якщо для якогось діапазону немає дескриптора, значить, на цій ділянці віртуальної пам'яті нічого немає, і доступ до такого діапазону неминуче веде до краху процесу. У разі, якщо для якогось діапазону закріплена фізична пам'ять, доступ до цим віртуальним адресами веде до звичайного доступу до фізичної пам'яті, таку пам'ять ще називають анонімною. У випадку, якщо файл відображений на віртуальну пам'ять, то при доступі за цими адресами зчитується частина файлу з диска у фізичну пам'ять, після чого доступ до неї буде виконуватися звичайним чином. Тобто ці два випадки дуже схожі, різниця лише в тому, що для останнього у відповідну фізичну пам'ять попередньо буде зчитана частину файлу. Про таких типах доступів дескриптор і містить інформацію. Ці дескриптори є структурами менеджера пам'яті, якими він управляє для того, щоб виконувати необхідні завдання. Як не важко здогадатися, для того, щоб вважати частину файлу сторінки фізичної пам'яті, менеджер пам'яті повинен надіслати запит файловій системі. На малюнку 2 зображено приклад віртуальної пам'яті процесу з двома діапазонами, А і В, доступ до яких ще ні разу не виконувався.

Малюнок 2


Діапазон А розташувати виконуваний файл самого процесу, а на діапазон відображена фізична пам'ять. Тепер, коли процес виконає перший доступ до діапазону А, управління отримає менеджер пам'яті і перше, що він зробить — оцінить тип діапазону. Оскільки на діапазон А відображений файл, менеджер пам'яті спочатку вважає файлу відповідну його частину у фізичну пам'ять, після чого відображає її на діапазон А процесу, таким чином подальший доступ до зчитаного вмісту буде виконуватися вже без менеджера пам'яті. Для діапазону менеджер пам'яті виконає таку ж послідовність, єдина різниця в тому, що замість зчитувань даних з файлу він просто відобразить вільні фізичні сторінки пам'яті на діапазон, після чого доступ до цього діапазону буде виконуватися вже без участі менеджера пам'яті. На малюнку 3 зображено приклад віртуальної пам'яті процесу після першого доступу до діапазонів А і В.

Малюнок 3


Як видно з малюнка, при доступі до обох діапазонах доступ до фізичної пам'яті виконується без участі менеджера пам'яті, оскільки раніше при першому доступі він відобразив на діапазони А й У фізичну пам'ять, а у фізичну пам'ять діапазону А попередньо вважав частину відповідного файлу.
Кеш менеджер є центральним механізмом для всіх відкритих файлів в системі на всіх дисках. Використання цього механізму дозволяє не тільки прискорювати доступ до файлів, але і економити фізичну пам'ять. Кеш менеджер не працює сам по собі, на відміну від менеджера пам'яті. Він повністю управляється файловими системами, і вся необхідна інформація про файли (наприклад, розмір) надається ними. Всякий раз, коли до файлової системи приходить запит на читання/запис, файлова система не читає файл з диска, замість цього вона викликає сервіси кеш менеджера. Кеш менеджер, у свою чергу, користуючись сервісами менеджера пам'яті, відображає файл на віртуальну пам'ять і копіює його з пам'яті в буфер запитувача. Відповідно, при доступі до цієї пам'яті менеджер пам'яті надішле запит файловій системі. І це буде особливий запит, який буде говорити, що файл треба вважати безпосередньо з диска. Якщо виконується доступ до файлу, який раніше вже було відображено кеш менеджером, то повторно відображений на віртуальну пам'ять він не буде. Замість цього кеш менеджер буде використовувати віртуальну пам'ять, куди файл був відображений раніше. Відображення файлу відстежується за допомогою структур, які файлові системи передають кеш менеджеру при виклику його сервісів. Про цих структурах трохи докладніше буде розказано нижче. На рисунку 4 наведено приклад читання файлу процесом.

Малюнок 4


Як показано на малюнку вище, процес виконує читання файлу в буфер Ст. Щоб виконати читання, процес звертається до менеджера введення/виводу, який формує і посилає запит файловій системі. Файлова система, отримавши запит, не зчитує файл з диска, а викликає кеш менеджер. Далі кеш менеджер оцінює, відображений файл на його віртуальну пам'ять, і якщо немає, то він викликає менеджер пам'яті для того щоб відобразити файл/частину файлу. В даному прикладі файл відображений, а доступ до нього жодного разу не виконувався. Далі кеш менеджер копіюються в буфер процесу файл, відображений на діапазон віртуальної пам'яті А. Оскільки доступ до діапазону А виконується перший раз, управління отримає менеджер пам'яті, потім він оцінить діапазон, і, оскільки це відображений на пам'ять файл, вважає його частина у фізичну пам'ять, після чого відображає її на діапазон віртуальної пам'яті А. Після цього, як вже було описано раніше, доступ до діапазону А буде виконуватися, минаючи менеджер пам'яті.
Ніщо не заважає одночасно кешувати файл і відображати його на пам'ять скільки завгодно разів. Навіть якщо файл буде закешований і відображений на пам'ять десятків процесів, фізична пам'ять, яка використовується для цього файлу, буде одна і та ж. В цьому і полягає суть економії фізичної пам'яті. На рисунку 5 наведено приклад, де один процес читає файл звичайним чином, а інший процес відображає цей файл на свою віртуальну пам'ять.

Малюнок 5


Як видно з малюнка вище, фізична пам'ять відображається на віртуальну пам'ять процесу і віртуальну пам'ять кеш менеджера. Коли процес буде виконувати читання файлу в буфер D, він звернеться до менеджера введення/виводу, який сформує запит і пошле файловій системі. Файлова система, в свою чергу, звернеться до кеш менеджеру, який просто копіює файл, відображений на діапазон віртуальної пам'яті, кеш менеджера, в буфер D процесу А. Оскільки в момент звернення до кеш менеджеру файл вже був не тільки відображено, але і раніше виконувався доступ до діапазону, на яку відображений файл, то операція буде виконана без участі менеджера пам'яті. Процес при читанні/запису діапазону Е по суті отримає доступ до тих же самим фізичним сторінок пам'яті, на якому при копіюванні файлу отримував доступ кеш менеджер.
Файлові системи приймають запити від користувача або інших драйверів. Перед доступом файл повинен бути відкритий. У разі успішного виконання запитів відкриття/створення файлів файлова система сформує структури пам'яті, які використовуються кеш менеджером і менеджером пам'яті. Також слід зазначити, що ці структури унікальні для файлу. Тобто якщо конкретний файл диска був відкритий на той момент, коли прийшов такий же запит на цей же файл, файлова система буде використовувати раніше сформовані структури пам'яті. По суті, вони є програмним поданням файлу диска в пам'яті. На малюнку 6 наведено приклад відповідності відкритих примірників файлів і їх структур.

Малюнок 6


На малюнку процес А відкрив файл та файл D, а процес B відкрив файл два рази. Таким чином, є три відкритих примірника файлу, коли структура, сформована файловою системою, всього одна. Файл D був відкритий один раз, отже, є один відкритий примірник, якому відповідає структура, сформована файловою системою.
Будь-які запити, спрямовані до файлової системи, не відразу обробляються нею. Запити спочатку проходять по ланцюжку драйверів, які бажають відстежувати такі запити. Такі драйвера називають фільтрами. Вони мають можливість переглядати запити до того, як вони досягнуть файлової системи, а також після того, як файлова система обробить їх. Наприклад, фільтр шифрування файлів може відстежувати запити читання/запису для того, щоб розшифрувати/зашифрувати дані. Таким чином, не допрацьовуючи самі файлові системи, ми можемо зашифрувати дані файлу. Фільтри можуть прив'язувати свої унікальні дані до структур файлів, які формує файлова система. Разом драйвера фільтрів і драйвер файлової системи формують стек файлової системи. Кількість фільтрів може бути різним, також можуть бути різними і самі фільтри. Теоретично їх може і не бути зовсім, але практично так не буває. На малюнку 7 зображено стек файлової системи, до складу якого входять три фільтра.

Малюнок 7


До того, як запит досягне файлової системи, він проходить послідовно через фільтри 1, 2 і 3. Коли запит буде оброблений файловою системою, то фільтрами він видно в зворотному порядку, тобто запит проходить послідовно через фільтри 3, 2 і 1. Також, на прикладі вище фільтр 1 і фільтр 3 прив'язали свої структури до структури файлу, яку сформувала файлова система після виконання запиту відкривання/створення файлу.
Переважна більшість завдань вирішується за допомогою фільтрації, але наш випадок унікальний. Як було раніше зазначено, унікальний він тим, що потрібно надавати одночасний доступ до зашифрованого і расшифрованному вмісту, а також зашифрувати імена файлів. Тим не менш, ми спробуємо розробити фільтр, який дозволить вирішити таку задачу.
На малюнку 8 зображена ситуація, коли файл був відкритий розшифрованим.

Малюнок 8


Це означає, що фільтри бачили розшифроване ім'я, і вони, як це зображено на малюнку, можуть прив'язати це ім'я до структури, яку сформує файлова система (як було раніше сказано, ця структура унікальна для конкретного файлу диска) для подальших маніпуляцій з файлом. І в цей момент файл відкривається зашифрованим, що означає, що фільтри бачили зашифроване ім'я. Як вони поведуть себе в такій ситуації, коли до структури файлу вже прив'язане розшифроване ім'я? Очевидно, що поведінка не передбачувано, хоча і не обов'язково, що наслідки будуть фатальними.
В продовження описаного вище можна додати, що при доступ до вмісту файлу також виникають проблеми, і набагато більш серйозні. Повернемося до ситуації, коли файл був відкритий одночасно розшифрованим і зашифрованим. Ця ситуація зображена на рисунку 9, читання/запис файлу ще жодного разу не виконувалися.

Малюнок 9


Тепер уявімо собі, що прийшов запит на читання розшифрованого вмісту. Файлова система скористається послугами кеш менеджера і передасть йому структуру файлу, до якої і кеш менеджер і менеджер пам'яті прив'яжуть свої унікальні дані для подальшого управління відображенням і кешуванням файлів. Ця ситуація зображена на рисунку 10.

Малюнок 10


Далі приходить запит на читання зашифрованого вмісту, і файлова система знову передає структуру файлу кеш менеджеру, а оскільки кеш менеджер і менеджер пам'яті раніше до цієї структури прив'язали унікальні дані цього файлу, вони просто скористаються ними для виконання запиту. Тобто тепер у цих структурах буде вказано, куди був відображений файл, і кеш менеджер просто копіює дані файлу віртуальної пам'яті в буфер запитувача. Ми пам'ятаємо, що файл при першому доступ до нього був закешований розшифрованим, таким чином при зашифрованому доступі в буфері запитувача виявляться розшифровані дані.
Ми розібрали дві фундаментальні проблеми. На практиці їх було більше. Наприклад, в рамках поставленої задачі до кожного зашифрованого файлу необхідно додавати заголовну інформацію, що теж не вирішується за допомогою фільтрації. Щоб вирішити всі ці проблеми разом, було знайдено рішення — віртуальна файлова система.
Віртуальна файлова система, по своїй суті, мало чим відрізняється від звичайної. Радикальна відмінність полягає в тому, що звичайна файлова система працює з диском, а віртуальна працює з файлами інших файлових систем, тобто є звичайним споживачем сервісів файлових систем. На малюнку 11 зображена концепція віртуальної файлової системи.

Малюнок 11


На відміну від звичайних файлових систем, віртуальна файлова система не реєструє себе в системі (про це не було сказано вище, але для того, щоб операційна система могла користуватися сервісами конкретної файлової системи, вона повинна зареєструватись) а раз так, то запити до неї надсилатися не будуть. Щоб вирішити цю проблему, ми використовуємо фільтр для звичайної файлової системи, але на цей раз його функції будуть дуже простими і обмеженими, одна з них (і головна) — це відстеження доступу до зашифрованих файлів. Як тільки фільтр побачить такий запит, він просто перенаправляє його до віртуальної файлової системи. Якщо ж буде виконуватися доступ до звичайного файлу, запит буде переданий оригінальної файловій системі.
Тепер давайте ще раз розглянемо розшифрований і зашифрований доступи, але вже в контексті віртуальної файлової системи. На малюнку 12 наведено приклад, коли виконувався доступ до расшифрованному і зашифрованого змісту конкретного файлу.

Малюнок 12


Ще раз уявімо ситуацію, коли файл був відкритий розшифрованим. Це означає, що в процесі виконання запиту відкривання файлу, наш фільтр побачив його і перенаправив на віртуальну файлову систему. Віртуальна файлова система, отримавши запит, оцінює тип доступу (розшифрований або зашифрований), і оскільки виконується розшифрований доступ, віртуальна файлова система спочатку перетворює розшифроване ім'я в зашифроване, а після спробує відкрити файл через рідну файлову систему з цього імені (тобто ім'я файлу на рідній файловій системі буде зашифрованим). У разі успіху віртуальна файлова система сформує структури пам'яті, які пізніше будуть використовувати кеш менеджер і менеджер пам'яті. Тепер уявімо собі, що файл відкривається зашифрованим, фільтр знову перенаправляє запит віртуальної файлової системи, не роблячи ніяких оцінок. Віртуальна файлова система оцінює тип доступу, а оскільки доступ зашифрований, вона просто спробує відкрити файл через рідну файлову систему з цього імені. І знову, в разі успіху, віртуальна файлова система сформує структури пам'яті для кеш менеджера та менеджера пам'яті. Але на відміну від розшифрованого доступу, це будуть вже інші структури. Тепер, якщо файл знову буде відкрито розшифрованим, віртуальна файлова система використовує ті ж структури, які сформувала при першому розшифрованому доступі. У разі якщо файл знову буде відкриватися зашифрованим, файлова система використовує структури, які сформувала при першому зашифрованому доступі. Таким чином, ми розділили доступ до расшифрованному і зашифрованого змісту.
На рисунку 13 зображена ситуація, коли доступ на читання/запис до расшифрованному і зашифрованим вмісту файлу ні разу не виконувався.

Малюнок 13


Тепер якщо буде виконуватися розшифроване читання, віртуальна файлова система, користуючись сервісами кеш менеджера, як показано на рисунку 14, передасть йому структури пам'яті, які вона повернула при відкриванні файлу розшифрованим.

Малюнок 14


Кеш менеджер відобразить файл на віртуальну пам'ять і скопіює дані в буфер запитувача. Відповідно, в процесі копіювання менеджер пам'яті надішле запит на читання віртуальної файлової системи, яка в свою чергу надішле запит на читання рідний файловій системі, а оскільки кеш менеджеру були передані структури пам'яті для розшифрованого файла, віртуальна файлова система розшифрує дані і повідомить про завершення менеджеру пам'яті, так закэшируется розшифроване вміст. У випадку, якщо буде виконуватися зашифроване читання, віртуальна файлова система передасть, як зображено на малюнку 15, кеш менеджеру структури пам'яті, які вона сформувала при відкриванні файлу зашифрованим.

Малюнок 15


Кеш менеджер знову відобразить файл на віртуальну пам'ять (оскільки в цих структурах файл ще не відображався) і скопіює дані в буфер запитувача. І знову в процесі копіювання менеджер пам'яті надішле запит на читання віртуальної файлової системи, яка знову надішле запит на читання рідний файловій системі, а оскільки кеш менеджеру були передані структури пам'яті для зашифрованого файлу, то, не розшифровуючи даних, віртуальна файлова система повідомить менеджеру пам'яті про завершення. Так файл закэшируется зашифрованим.
Як ми бачимо, віртуальна файлова система вирішує фундаментальні проблеми, що не дозволяють мати одночасний доступ до расшифрованному і зашифрованим вмісту файлу, з-за чого доводиться відмовлятися від класичних механізмів операційної системи. В процесі фільтрації ми можемо тільки додавати дані до структур пам'яті файлів, які повертає файлова система, і, оскільки ми не формуємо ці структури, ми не можемо втручатися в них і керувати ними. А за допомогою віртуальної файлової системи ми їх повністю формуємо, і, отже, маємо повний контроль над ними, що необхідно в рамках вирішення даної задачі. Наприклад, нам потрібно забезпечувати узгодженість розшифрованого і зашифрованого содержимых файлів. Уявіть собі ситуацію, коли були записані дані в розшифрований файл і дані знаходяться ще в кеші, а не на диску. І в цей момент приходить запит на читання зашифрованого вмісту файлу. У відповідь на це віртуальна файлова система вивантажить розшифроване вміст на диск і скине зашифрований кеш, що змусить кеш менеджер заново послати запит на читання віртуальної файлової системи для зашифрованого читання. В рамках фільтрації подібне завдання не вирішується в принципі.
При розробці віртуальної файлової системи доводилося стикатися з незвичайними проблемами. Почасти це викликано тим, що ми працюємо з файлами файлових систем, коли звичайні файлові системи працюють з диском. Так, наприклад, була знайдена помилка в файловій системі NTFS. Проявлялася вона в тому, що доступ до файлу X:\$mft\<будь-яке ім'я> приводив до повисанию всього доступу до диска X. В результаті дослідження було встановлено, що NTFS не звільняла механізми синхронізації файлу $mft, який є перечислителем всіх файлів диска. І відповідно, щоб знайти який-небудь файл на диску, спочатку потрібно прочитати $mft файл, доступ до якого повис. Інший приклад, який можна назвати незвичайним, це знайдена помилка в ядрі Windows 8, в результаті якої менеджер пам'яті вважає, що структури пам'яті файлу завжди останньої версії. З-за цього він намагається використовувати деякі частини цієї структури, яких насправді може не бути. І це призводило до BSOD.
Реалізація віртуальної файлової системи значно складніше реалізації фільтра, але наявність такого механізму дає більшу гнучкість при маніпуляціях з файлами. В тому числі таку, про яку ми тільки що говорили. Хоча, на перший погляд, може здатися, що завдання тривіальна.
В результаті застосування даного підходу до шифруванню були успішно реалізовані функції надання одночасного доступу програмних процесів до зашифрованого і расшифрованному вмісту, а також реалізовано шифрування імен файлів, що дозволяє забезпечити високу ступінь прозорості при реалізації криптографічного захисту інформації.
Треба зазначити, що даний підхід до забезпечення «прозорості» шифрування файлів в ОС Windows успішно реалізований в корпоративному продукті Secret Disk Enterprise («Аладдін Р. Д.»), який застосовується багатьма організаціями в Росії. Це в свою чергу доводить життєздатність і перспективність застосування цієї ідеї в процесі створення програм шифрування файлів на диску.
В якості висновку слід зазначити, що технологічна складність файлової системи ОС Windows і відсутність стандартних механізмів вирішення завдань, подібних до описуваної в даній статті, будуть завжди бути перешкодою створення зручних і простих програм, що забезпечують захист інформації. У такому випадку єдиним вірним рішенням є самостійна реалізація оригінального механізму, що дозволяє обійти ці обмеження без втрати функціональності.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.