Трунов Д.Н.
PASSWORDKEEPER 4.
ОСОБЕННОСТИ РЕАЛИЗАЦИИ НОВОЙ ВЕРСИИ
ПРОГРАММЫ ДЛЯ ХРАНЕНИЯ ПАРОЛЕЙ
Введение
С одной стороны,
использование любой специализированной
программы для хранения паролей — уже
лучше хранения паролей в открытом виде
в текстовом файле или электронной
таблице. Такой файл может быть с лёгкостью
открыт другим пользователем компьютера
или попасть в чужие руки с утерянной
флешкой или из-за утечки в облачном
хранилище [1]. С другой стороны, использование
программы для хранения паролей как бы
говорит всем: пароли здесь. Чем популярнее
программа, тем сильнее интерес к ней
злоумышленников. Нельзя исключать и
того, что недобросовестные разработчики
могут целенаправленно включить в свою
программу лазейки для кражи паролей
пользователей.
Выбирая решение
для хранения паролей можно исходить из
доверия к компании-разработчику и/или
опыту сообщества пользователей. Как
правило, крупные компании дорожат своей
репутацией, чтобы выпускать заведомо
небезопасный продукт. Польза от кражи
пользовательских паролей обычно явно
ниже, чем ущерб от потери доверия клиентов
и падения продаж. Что касается программ
с открытым исходным кодом, то в отсутствии
в них уязвимости и лазеек может убедиться
каждый, изучив текст программы.
Но в любом правиле
могут быть исключения. Репутация
разработчика или открытый исходный код
не являются стопроцентной гарантией
надёжности, поскольку пользователь не
может контролировать процесс создания
программы и выхода для неё обновлений
(точно ли очередное обновление призвано
улучшить защиту?). Поэтому ещё одним
вариантом является выбор в пользу
контроля над созданием программы. Это
либо написание её самостоятельно, либо
собственноручная сборка из исходных
текстов (после тщательной их проверки).
Идея программы
PasswordKeeper
Идея написания
собственной программы для хранения
паролей, прежде всего, преследует цель
полного контроля над разработкой с
гарантией отсутствия заведомых лазеек
в защите. Реализация лишь наиболее
необходимых функций упрощает программу
и облегчает её анализ на предмет наличия
ошибок и уязвимостей. При этом есть
возможность реализовать полезные
функции, отсутствующие в других решениях.
Надёжная программа
для хранения паролей должна применять
стойкое шифрование, чтобы файл с паролями,
попади он в руки злоумышленнику, не был
открыт без знания секретного ключа.
Также работающая программа должна иметь
защиту против попыток вредоносных
программ, запущенных в той же системе,
получить доступ к сохранённым паролям
или ключу. И, как уже упоминалось, не
иметь заведомо оставленных лазеек.
Если возложить
функции защиты от возможных вредоносных
действий других программ на операционную
систему (антивирус, фаервол), то задача
может несколько упроститься: достаточно
будет реализовать стойкое шифрование
и обеспечить отсутствие лазеек. Остальную
защиту выполнять средствами операционной
системы и специализированных программ.
Требования к
программе PasswordKeeper 4
Основной целью
создания новой (4-й) версии программы
PasswordKeeper является доработка и улучшение
функций предыдущей (3-й) версии программы
[2], с учётом анализа преимуществ и
недостатков существующих программ для
хранения паролей, в частности KeePassXC [3].
При этом к программе предъявляются
следующие требования:
1) она должна быть
портативной и выполняться без установки
и дополнительной настройки на операционных
системах Windows и Linux;
2) в отличие от
предыдущей версии, парольные записи в
новой программе не должны ограничиваться
только заголовком и паролем с заметкой:
нужны дополнительные поля для хранения
названий сайтов или программ, а также
логинов;
3) при изменении
сохранённого пароля предыдущий должен
сохраняться в истории. Нужны функции
работы с историей паролей: копирование
паролей из истории или их удаление;
4) функцию изменения
порядка парольных записей необходимо
исключить, а вместо неё реализовать
отображение записей в алфавитном
порядке;
5) для удобства
работы необходима возможность разделять
записи по папкам или категориям;
6) как и в KeePassXC,
необходима возможность работать с
файлами-ключами;
7) необходима
возможность генерировать файл-ключ по
заданному паролю (чего нет в KeePassXC).
Основная реализация
программы
Для реализации
кроссплатформенности была выбрана
среда разработки Lazarus [4], позволяющая
создавать программы и для Windows, и для
Linux, причём с минимальными изменениями
(или вообще без них) в исходном коде.
Для организации
работы с записями было решено применить
такую динамическую структуру данных,
как упорядоченный список [5]. Для этого
в программе объявляется два типа данных:
запись NoteR и ссылка на неё TNote. Переменная
FirstNote типа TNote ссылается на первую запись
или содержит Nil (если записей нет). Ниже
приведено объявление типов NoteR и TNote:
type
NoteR
= Record
Title:
String; // заголовок записи
Site: String; // название сайта/приложения
Login:
String; // имя пользователя/логин
Categ:
String; // категория записи (ярлык)
Prot: Array of Byte; // защищённая шифрованием часть
Len: Word; // размер защищённых данных
Next: Pointer; // ссылка на следующую запись
end;
TNote
= ^NoteR;
Каждая запись
содержит заголовок Title, название сайта
Site, имя пользователя Login, название
категории Categ, массив защищённой части
Prot, размер зашифрованных данных Len и
указатель на следующую запись в списке
Next (для последней записи в списке Next =
Nil). Защищённая часть Prot хранит в
зашифрованном виде пароль, историю
паролей и заметку.
При добавлении
записи создаётся новая динамическая
переменная типа TNote, и в ней устанавливаются
значения полей. Добавляемый пароль,
история (в новой записи она пустая) и
заметка объединяются в одну строку
через специальные символы-разделители.
Затем эта строка преобразуется в байтовый
массив соответствующей длины и
зашифровывается блочным шифром.
Полученный массив (точнее, ссылка на
него) помещается в поле Prot, а в поле Len
сохраняется длина объединённой строки
(размер зашифрованного массива может
быть больше изначальной длины строки,
потому Len будет нужна для корректной
расшифровки).
Добавление
полученной записи в список осуществляется
обычным для списков способом: определяется
позиция записи в списке, указатель Next
предыдущей записи копируется в указатель
добавляемой записи, а в указатель
предыдущей помещается ссылка на текущую
запись. После добавления предыдущая
запись будет указывать на текущую, а
текущая — на следующую (на которую ранее
ссылалась предыдущая). Если добавляется
самая первая запись, то ссылка на неё
помещается в FirstNote, а поле Next записи
должно содержать Nil (пустой указатель).
Позиция добавляемой
записи в списке определяется исходя из
условия соблюдения упорядоченности
списка по заголовкам Title. При поиске
позиции для добавления проверяются
заголовки всех записей, пока не будет
найдена подходящая позиция или пока не
завершится список. Во втором случае
новая запись будет добавлена в конец
списка.
При удалении записи
значение указателя Next предыдущей записи
меняется на значение указателя текущей
и, таким образом, удаляемая запись
исключается из списка. После этого
освобождается массив защищённой части
Prot, а затем — вся удаляемая запись.
Изменение
существующей записи осуществляется
следующим путём. Запись открывается с
расшифровкой и извлечением защищённой
части: пароль+история+заметка. История
паролей сохраняется и к ней добавляется
текущий пароль (если он изменился, иначе
история остаётся неизменной), после
чего запись удаляется и добавляется
заново в изменённом виде вместе с
существующей историей. Историю паролей
тоже можно менять, удаляя из неё либо
отдельные пароли, либо все вместе.
После любой операции
добавления, изменения или удаления
записи весь список сохраняется в ранее
созданный для этого или открытый
файл-хранилище.
Реализация
шифрования и сохранения/загрузки
хранилища записей
Схема шифрования
в PasswordKeeper 4 реализована с участием трёх
алгоритмов авторской разработки: блочный
шифр ESCK-6[6], потоковый шифр ШОРТ (Short)[7] и
алгоритм хеш-функции CSA-3[8]. При каждом
создании нового хранилища или при
открытии существующего создаётся
экземпляр блочного шифра Cyp на основе
введённого мастер-пароля Password с
количеством циклов (количеством
повторений главного цикла шифрования)
Cycles. Этот шифр потом необходим для
шифрования/расшифровки защищённых
массивов Prot записей.
Кроме шифра Cyp,
вычисляется также строка Psw. Для её
вычисления сначала создаётся шаблонный
массив Mass, «расшифровывается» шифром
Cyp, а затем хешируется по алгоритму CSA-3
с количеством циклов, равным 10000. В строке
Psw сохраняется результат хеширования.
Ниже приведён фрагмент текста программы:
//
создать блочный шифр и генерировать
ключ
Cyp :=
ESCK6Cypher.Create;
Cyp.Gen(Password,
Cycles, mdRndm);
Password
:= '';
//
создать шаблонный массив и "расшифровать"
полученным ключом
for I :=
0 to 2047 do
Mass[I]
:= I;
Cyp.DecryptMass(Mass,
2048);
//
хешировать полученный массив и освободить
созданный экземпляр H
H :=
CSA3Hash.Create;
Psw :=
H.HashMass(Mass, 2048, 10000);
H.Free;
«Расшифровка»
шаблонного массива нужна, чтобы
преобразовать его с помощью полученного
ключа Cyp, который, в свою очередь, зависит
от мастер-пароля Password. Можно было
применить и зашифровку — суть от этого
сильно не меняется. Только при другой
длине массива это могло бы породить
проблему: из-за возможного добавления
случайных данных в конец неполного
блока результат зашифровки может быть
каждый раз разный, тогда разными будут
и результаты вычисления Psw.
Строка Psw нужна
для создания потокового шифра, которым
шифруются или расшифровываются записи
при каждом сохранении в файл или чтении
из него. При сохранении списка записей
вначале генерируется «соль» — строка
Salt, содержащая случайные символы. Она
сохраняется в файл для возможности
последующей расшифровки. Соответственно,
при чтении списка записей строка Salt
будет просто прочитана из файла.
Затем строка Salt
хешируется по алгоритму CSA-3 с ранее
полученной строкой Psw в качестве пароля
хеша. Полученный хеш в виде строки S
вместе со строкой FKHash (будет рассмотрена
далее) участвует в создании потокового
шифра. Ниже приведён фрагмент текста
программы:
//
хешировать полученную "соль" с Psw
в качестве пароля
H :=
CSA3Hash.Create;
H.SetPassword(Psw);
S :=
H.HashString(Salt, Cycles + 10000);
//
создать потоковый шифр с ключом на
основе полученного хеша
// и
хеша файла-ключа (если не пустой)
SC :=
ShortCypher.Create;
SC.Gen(S
+ FKHash, Cycles);
При сохранении
списка записей каждая запись вначале
преобразуется в байтовый массив. В этот
массив (через символы-разделители)
вписываются все поля записи (Title, Site,
Login, Categ), а затем присоединяется защищённая
часть Prot. Затем весь массив шифруется
полученным потоковым шифром и записывается
в файл. Предварительно в этот файл нужно
лишь вписать параметры сохраняемой
записи: размер полей записи, размер
защищённого массива Prot и величину Len.
Чтение производится в обратной
последовательности: читаются параметры
записи, затем читается сама запись в
массив, массив расшифровывается потоковым
шифром и из него извлекаются поля записи
(Title, Site, Login, Categ).
Также в конец файла
записывается 32-битная контрольная
сумма, которая считается перед шифрованием
записей потоковым шифром. При чтении
файла контрольная сумма считается после
расшифровки записей потоковым шифром
и позволяет убедиться в правильной
расшифровке записей и целостности
файла.
Как видно, в
программе применяется двухуровневое
шифрование двумя разными шифрами:
блочным и потоковым. Блочный шифр
создаётся непосредственно на основе
мастер-пароля и необходим для шифрования
добавляемых паролей, их истории и
заметок. Потоковый шифр зависит не
только от мастер-пароля, но и от случайной
строки Salt, которая создаётся заново при
каждом сохранении файла. Это обеспечивает
в каждом случае создание уникального
ключа шифрования. При этом менее
защищённая часть (заголовки, логины и
т.д.) шифруются только потоковым шифром,
а пароли и заметки — и потоковым, и
блочным, что обеспечивает повышенную
защиту от возможного взлома.
Функции работы
с файлом-ключом
Файл-ключ предназначен
для повышения надёжности шифрования и
усиления защиты от взлома файла-хранилища.
Не зная мастер-пароль, но имея на руках
защищённый файл, мастер-пароль можно
попросту подобрать. Использование
файла-ключа позволяет этого избежать
(если этот файл хранится отдельно от
файла с паролями).
Когда файл-ключ
подключается к программе, вычисляется
его хеш и помещается в строку FKHash. Эта
строка (если она не пустая, когда файл-ключ
не подключен) участвует в создании
потокового шифра при открытии и сохранении
файла паролей. При отсутствии файла-ключа
становится практически невозможным
создать правильный ключ потокового
шифра и расшифровать сохранённые в
файле записи.
В программе
реализованы также функции создания
файла-ключа. Одна из них создаёт файл-ключ,
заполненный случайными байтами.
Недостаток такого файла в том, что нужно
обеспечивать его сохранность и при этом
обязательно хранить его отдельно от
файла-хранилища. Если такой файл-ключ
будет утерян, восстановить его будет
невозможно, как невозможно будет и
открыть файл-хранилище.
Альтернативой
является создание файла-ключа по паролю.
Для этого создаётся шаблонный массив
M размером FKSize и шифруется потоковым
шифром, созданным на основе заданного
пароля P. Ниже приведён фрагмент кода
программы:
//
заполнить массив шаблонными числами
for I :=
0 to FKSize - 1 do
M[I]
:= I;
//
создать шифр, зашифровать массив,
освободить шифр
S :=
ShortCypher.Create;
S.Gen(P,
Cycles);
S.EncryptMass(M,
FKSize);
S.Free;
Полученный
зашифрованный массив остаётся только
записать в новый файл и файл-ключ готов.
Преимущество этого способа в том, что
беспокоиться о сохранности файл-ключа
не нужно: в случае его утери такой же
файл-ключ можно создать заново — нужно
только помнить пароль или хранить его
в надёжном месте. Ко всему прочему,
полученный файл-ключ можно применять
также в KeePassXC и некоторых других
программах.
Другие функции
и особенности
Как и в предыдущей
версии, в PasswordKeeper 4 реализована функция
замены мастер-пароля, генератор случайных
паролей, поиск по записям, а также функция
создания кода восстановления мастер-пароля
(и восстановления мастер-пароля по этому
коду). Но есть и некоторые различия. Так,
из новой версии был исключён контроль
доступа по PIN-коду. Теперь при каждом
обращении к записям вводить PIN-код не
требуется. Вместо этого реализована
блокировка программы после некоторого
периода неактивности, а для разблокировки
необходимо опять вводить мастер-пароль.
Также из программы
исключена виртуальная клавиатура для
ввода паролей. Она могла бы быть полезной
при наличии риска перехвата вводимых
паролей. Однако при наличии такого риска
лучше вообще не пользоваться программой
либо использовать виртуальную клавиатуру
сторонних разработчиков.
Другое нововведение
— это работа с категориями. При добавлении
каждого нового пароля для него можно
указывать категорию, а потом в главном
окне отображать записи только выбранных
категорий — это повышает удобство
работы с паролями. Поиск по пустой строке
позволяет отобразить записи, не
принадлежащие ни к одной из существующих
категорий.
Создавать и
открывать теперь можно произвольные
файлы-хранилища, а не единственный
установленный по умолчанию. При этом
были исключены функции резервного
копирования таких файлов: работа с
резервными копиями должна производиться
средствами операционной системы.
Значение количества
циклов шифрования устанавливать при
каждом создании файла-хранилища или
замене мастер-пароля теперь не нужно:
это значение установлено по умолчанию.
Однако установленное по умолчанию
значение можно изменить в настройках
(изменение действует только до завершения
программы или до следующего изменения).
Заключение
Как видно, все
основные требования, поставленные перед
новой версией PasswordKeeper, были выполнены.
Применение среды разработки Lazarus
позволяет относительно легко создавать
сборки программы для разных операционных
систем, в том числе Windows и Linux. Улучшенная
схема работы с записями в виде
упорядоченного списка позволила решить
одновременно несколько задач. Во-первых,
реализовать дополнительные поля записей,
в частности, название сайта и логин.
Во-вторых, позволила сортировать записи
в алфавитном порядке ещё на этапе их
добавления. В-третьих, это облегчило
реализацию работы с категориями, которая
сама по себе существенно облегчает
работу с паролями и навигацию по ним.
Реализована также
работа с историей паролей и некоторые
другие полезные функции. Теперь при
изменении пароля его прежняя версия
сохраняется в истории. Историю можно
открыть для просмотра, скопировать
выбранный пароль в буфер обмена или
удалить его (или даже очистить всю
историю). Вместо неудобного ввода
PIN-кода при каждом обращении к записям
реализована блокировка открытого
хранилища паролей после некоторого
периода неактивности.
Кроме этого, в
PasswordKeeper 4 была реализована более надёжная
схема двухуровневого шифрования с
применением блочного и потокового
шифров. Схема генерации ключей шифрования
устроена таким образом, что позволяет
легко включать в неё файл-ключ кроме
основного пароля (мастер-пароля). При
этом реализованы две функции для создания
файлов-ключей: одна создаёт случайный
файл-ключ, а вторая — по заданному
паролю.
Источники
информации
1.
Рафаэль Фахрутнидон. Google заявил о
непричастности к утечке // Газета.ru
[Электронный ресурс] — URL:
https://www.gazeta.ru/tech/2018/07/05_a_11827645.shtml
2.
Трунов Д.Н. Компьютерная программа
PasswordKeeper для безопасного
хранения паролей и заметок к ним.
[Электронный ресурс] – URL:
http://d-raft5.blogspot.com/2018/08/passwordkeeper.html
3.
KeePassXC. The Project [Электронный ресурс] – URL:
https://keepassxc.org/project
4.
Overview
of Free Pascal and Lazarus/ru [Электронный
ресурс] – URL:
https://wiki.lazarus.freepascal.org/Overview_of_Free_Pascal_and_Lazarus/ru
5.
Методические указания и задания к
лабораторным работам по курсу «Алгоритмы
и структуры данных» (направление
подготовки 6.050103 «Программная инженерия»).
Сост.
Г.Г. Шалдырван, Н.С. костюкова. - Донецк, 2009. - 114 с.
Г.Г. Шалдырван, Н.С. костюкова. - Донецк, 2009. - 114 с.
6.
Трунов Д.Н. От ESCK-5 к ESCK-6:
основные отличия нового алгоритма
шифрования. [Электронный ресурс] – URL:
http://d-raft5.blogspot.com/2018/12/esck-5-esck-6.html
7.
Трунов Д.Н. Реализация потокового шифра
на основе алгоритма ESCK-6,
его применение и оценки надёжности.
[Электронный ресурс] – URL:
https://d-raft5.blogspot.com/2019/06/esck-6.html
8.
Трунов Д.Н. Алгоритм криптографической
хеш-функции CSA-3 [Электронный ресурс] –
URL: https://d-raft5.blogspot.com/2019/10/csa-3.html