Closed alexivanou closed 7 years ago
У вас есть возможность записать скринкаст? В linux можно воспользоваться recordmydesktop.
Какая операционка? Какая битность?
Да, и еще, что испорчено - html-файл записи, или xml файл дерева?
Так, походу нащупал, скринкаст не нужен. Предварительно могу сказать, что этот баг появляется только в момент начала шифрования (то есть, если ветка до этого не была зашифрована) и только с первой записью, с которая была открыта в момент шифрования, и только если продолжить редактирование без переключения на другую запись. Файл базы XML не портится, сбивается содержимое файла записи.
Я такого бага за все года заметить не мог, потому что у меня зашифрована одна большая ветка, и записи создаются внутри нее, то есть когда создается запись, ветка уже зашифрована.
Вы же наткнулись на граничный эффект - редактируется запись, ветка шифруется, запись продолжает редактироваться. Вот последовательность действий:
Баг подтверждаю, буду смотреть как исправить.
Дополнение, только что проверил по следующей схеме:
Есть еще 2 замечания, наличие которых заставили вернуться на CherryTree:
С картинкой все нормально, так и должно быть. Нигде не обещалось, что будут шифроваться картинки. Шифруется текст, шифруются аттачи. Картинки пока не шифруются по причине того, что в HTML-движке QTextEdit не перехватываются обращения к картинкам. Поэтому вместо подмены метода получения картинки, придется городить шифровку и расшифровку в отдельном каталоге, потому что к тому же в плюсах до сих пор нет кроссплатформенного решения по представлению файла в памяти - под Linux проблем нет, а в Windows болт. Шифрование картинок у меня давно записано в хотелках, надо этим заняться. Но пока не решил как правильнее сделать.
То что пустой каталог остается от удаленной ветки - посмотрю, хотя это некритично, но и некрасиво.
По поводу XTS вот здесь я даже описания его не вижу: https://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B6%D0%B8%D0%BC_%D1%88%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F
Пароль в памяти в открытом виде не хранится. Вычисляется его хеш, и он используется как ключ шифрования.
По поводу шифрования - возможно, когда я соберусь делать нормальный веб-клиент, мне понадобится реализация шифрования на JavaScript, чтобы пароль (точнее хеш) был только в браузере пользователя, чем обеспечивалось бы безопасное хранение данных на недоверенном сервере. Поэтому мне нужно шифрование достаточно простое и эффективное. Как считаете, реализация AES-256 будет такой же быстрой как RC5 с CBC на JavaScript
С картинкой можно сделать проще - кодировать её в base64 и вставлять в стили html. Тогда зашифруется вместе с текстом, правда за счет увеличения размера. Хорошей практикой является перед шифрованием текста обрабатывать его алгоритмом архивации. Я бы смотрел в сторону 7zip, по личным наблюдениям справляется с текстом на уровне RAR, но более надежен (в плане меньше косяков от версии к версии возникает).
По XTS вот хороший наглядный пример в сравнении с CBC даже: https://www.kingston.com/ru/usb/encrypted_security/xts_encryption А вот реализация самого алгоритма с пояснениями: https://habrahabr.ru/post/120096/
По поводу javascript: да, библиотеки есть. Например, эта https://github.com/ricmoo/aes-js Но есть замечания:
Для веб-компоненты я бы вообще не рекомендовал заниматься разработкой шифрования. Время говорит, что в вебе информация защищена не более, чем защищен сервер, клиент и канал вместе взятые. Полностью защищенный трафик только в 10% коммерческих компаний. Ко всем остальным есть варианты подходов.
Если есть большая нужда иметь доступ к приватной зашифрованной информации с удалённого места, нужно думать о разработке собственного клиента, либо настроек в программе удаленного подключения к (например) ftp, googleDrive и т.п. Тогда есть шанс защитить клиента от угроз и обеспечить надежный канал до данных.
Добавочка
/libraries/crypt/password.cpp строка 55-56:
// В этом месте пароль введен правильно и подтвержден пользователем
QString password=enterPwd.getPassword();
В этом месте из диалогового окна получается строка, которая копируется в новый объект, а старая строка в диалоговом окне "уничтожается", т.е. о ней просто забывается и надеемся на уборщик мусора. А уборщик обнулять память не станет, он только пометит в таблицах свободных блоков, что эти блоки свободны и всё. Т.е. если зачитать дамп памяти, то получим пароль в открытом виде.
Безопасно было бы в конструктор диалогового окна передавать ссылку на объект строки, в который хотим получить результат, чтобы потом его использовать и исключить дублирование пароля в оперативке.
Плюс далее по тексту
// Вычисляется и запоминается в память ключ шифрования
setCryptKeyToMemory(password);
но при этом:
void Password::setCryptKeyToMemory(QString password)
Таким образом еще раз создается копия пароля в памяти и передается в функцию, уничтожаясь тоже через сборщик мусора. В принципе, там везде такие вызовы.
Рекомендовал бы почитать литературу на тему указателей и ссылок на переменные. В идеале во всей программе должна быть одна область памяти, адрес которой передается во все места, работающие с паролем. Но при этом в ней не должно быть пароля, а уже на этапе его ввода пользователем туда должен сохраняться его хеш.
И забыл еще по скорости работы AES и RC5 в режимах CBC и XTS. AES и RC5 на одном и том же железе работают одинаково по скорости (плюс-минус пару процентов). Но если AES шифруется инструкциями процессора, а RC5 нет, то тут AES обгоняет по скорости минимум в 2-3 раза http://www.thg.ru/cpu/aes_clarkdale/print.html XTS режим будет медленнее CBC, т.к. там по сути каждый блок шифруется 2 раза, но это не значит, что он будет в 2 раза медленнее, т.к. затрат на передачу блока из памяти в процессор не будет. Я бы сказал, что XTS будет процентов на 30 медленнее CBC.
Если бы алгоритм RC5 реализовали аппаратно на большом количестве бюджетных процессоров, я бы агитировал за него, т.к. по стойкости это одинаковые звери.
А по поводу скорости работы шифрования в Javascript вообще беспокоиться не стоит. Но не потому, что там всё хорошо. Тормоза будут в любом случае отменные. Но ни гугл, ни мозила, ни микрософт не станут с этим что-то делать и как-то ускорять. И тем более яваскрипту никогда не позволят иметь доступ к аппаратной части (чтобы, например, воспользоваться aes-ni). И еще тем более, что один и тот же код JS работает с разной скоростью в разных браузерах в виду различий в интерпретаторах. Поэтому, выбрав любой алгоритм шифрования получаем лучшее время в одном-двух браузерах из всего списка. Выбрав другой алгоритм, получаем лучшее время в других браузерах. Бессмысленно с точки зрения хранения информации. Только если сервер будет перекодировать и выдавать в том виде, в котором данный конкретный браузер преуспел. Но тогда проще опять же обеспечить SSL/TSL и выдавать уже расшифрованный текст - в 2 раза дешевле и быстрее.
XTS использует два ключа AES. Один ключ используется для выполнения блочного шифрования AES; другой используется для шифрования "Tweak Value" (значения поправки). Эта зашифрованная поправка затем изменяется с помощью полиномиальной функции Галуа (GF) и XOR с обычным и зашифрованным текстом каждого блока. Функция GF обеспечивает дополнительное размытие и обеспечивает отсутствие превращения блоков одинаковых данных в одинаковый шифрованный текст. Это позволяет превращать каждый блок в уникальный шифрованный текст при одинаковом обычном тексте без использования векторов инициализации и сцепления блоков.
Вот этого я не понял. Например, имеем два AES ключа (это секреты) и открытый текст. Получается что если этот открытый текст первый раз зашифровать через XTS, и открытый текст второй раз зашифровать через XTS, то получится вообще разные данные, так как если бы каждое шифрование проводилось с разными инициализирующими векторами?
Предположим, мы имеем пользовательский пароль любой длины. Для AES нам нужно 256 бит ключ. Т.е. мы должны либо расширить, либо сократить введенный пароль пользователя до длины 32 байт. Обычно можно сделать SHA256 - и получим уникальный ключ, привязанный к исходному паролю пользователя. Но если мы сделаем SHA512, то получим 2 раза по 256, т.е. 2 ключа, одновременно привязанных к исходному паролю пользователя. При этом с помощью первых 256 бит мы можем шифровать сам текст, а вторые использовать для вычисления инициализирующего вектора, опять же на основании исходных данных, или просто захешить, или еще как-либо.
Я думаю, нужно думать в эту сторону. По поводу шифрования два раза и получения разных данных ситуацию представить не смог.
Неправильное шифрование текущей записи, редактируемой в момент переключения ветки в шифрованное/нешифрованное состояние исправлено.
https://github.com/xintrea/mytetra_dev/commit/f898f535d707798fab0509da863bd79f5ff9736f
Удаление пустой директори при удалении записи, набора записей или ветки исправлено, теперь правильно удаляется и в режиме портабельного приложения, и в режиме инсталлируемого.
https://github.com/xintrea/mytetra_dev/commit/c6972ae7d5d5dde49ccac94868e44e1c6dc5f24f
Прошу проверить и закрыть баг (что то я не могу найти где я сам могу этот баг закрыть, возможно это должен сделать автор бага).
Создал новую ветку, разместил в ней запись, зашифровал ветку. Всё ок, файл зашифрован. Перезапускаю программу, перехожу в ветку, ввожу пароль - запись видна, всё ок. Редактирую запись, добавляю в неё картинку, кучу текста. Смотрю в файл - всё лежит в открытом виде. Удивляюсь, перезапускаюсь, просит пароль (еще раз проверяю - данные лежат в открытом виде). После ввода пароля вижу пустой лист с данными, а файл базы безнадежно испорчен (полагаю, процедурой дешифровки). Маленький пушистый зверёк.