MMMAAANNN писал(а):
Приватный ключ используется только при создании клавограммы и привязан к автору. Публичный ключ позволяет считать зашифрованную клавограмму, но изменить ее не зная приватного ключа не получится.
То есть чтобы нельзя было взять клавограмму кибергонщика и чуть-чуть поправив задержки выдать за свою.
В этом случае ты делаешь невозможным сохранять клавограмму
за авторством этого кибергощника. Однако ты по-прежнему можешь подписать любую клавограмму (в том числе искусственно созданную) своим приватным ключом, тем самым выдав за свою.
Придерживаюсь такого же мнения, что и
ergozorax: без закрытого кода цифровую подпись для определения легитимности клавограмм сделать не получится. Плюс к этому, как показывает практика, если кому-то очень-очень захочется, то даже закрытый код не является препятствием при наличии должных навыков.
Однако все эти рассуждения касаются небольшой части функционала ТСки, и в общем-то этот модуль можно вынести в отдельную shared библиотеку, а остальное вполне можно сделать opensource.
Общая архитектура может быть, например, такой:
скрытый текст…
```mermaid
flowchart TD
subgraph library["Shared library *.dll*.so"]
core
logger
end
subgraph core
analyzer -.- CA
end
subgraph logger
x11
winapi
end
core --- logger
ffi["FFI"] --- library
tcp["TCP server"] --- ffi
web["WEB server"] --- ffi
shell --- ffi
subgraph gui1["GUI Application"]
desc1["connection via TCP"]
end
subgraph gui2["GUI Application"]
desc2["connection to localhostnvia HTTP(S)"]
end
subgraph gui3["GUI Application"]
desc3["call external library functionsndirectly via FFI"]
end
gui1 --- tcp
gui2 --- web
gui3 ---- ffi
```
На картинке (в нижней части) подгружаемая библиотека *.dll/*.so с торчащим наружу FFI. GUI приложения (верх укартинки) будут выступать в качестве клиентов, общаясь с библиотекой непосредственно через интерфейс FFI, либо через посредников в виде запущенного TCP/HTTP сервера. В последнем случае GUI можно будет сделать как обычное web-приложение (сайт).
Пояснения, касающиеся подгружаемой библиотеки. Должна реализовывать:
- Логгер (под каждую платформу), перехватывающий все события нажатия клавиш клавиатуры;
- Хранение всех событий нажатия клавиш. Каждому событию присваивает свой уникальный ID (скорее всего в качестве идентификатора можно применить метку времени самого события);
- Обработку запросов, поступивших извне (через FFI), в том числе:
- включать отключать логгер
- загрузку и сохранение клавограмм
- свой статус в трее (активен перехват или нет)
- ограниченное радактирование сохранённых событий, в основном их удаление: частичное или полное (очистка)
- ...
Отдельно хочу заострить внимание на обеспечение валидности клавограмм в момент сохранения. Обеспечить это можно только если
не отдавать наружу зафиксированные события во избежание их изменения извне. То есть не получится возвращать указатель на запрашиваемые события клавиш, все данные придётся копировать в предоставляемый со стороны GUI буффер. Это маленькая, но важная деталь. На практике это означает чуть больше кода и в два раза больше объёма оперативы :)), но скорее всего это несущественно.
Итого, сохранять в файл будет сама библиотека. GUI-клиент передаёт два идентификатора событий (начало и конец клавограммы) и все события в этом промежутке будут отобраны, сериализованы в поток готовых байтов, а также добавлена цифровая подпись.
Между графикой (GUI) и библиотекой есть обширная задача по анализу сырых событий нажатий клавиш. Решение этой задачи можно вынести в отдельный модуль (анализатор), который будет рассчитывать статистику. Тут никаких секретов не требуется, так что он тоже может быть с открытым исходным кодом. И хотя может показаться, что это какая-то простая фигня, на деле это не так. Так как события перехватываются и хранятся сырыми (пусть даже приведённые из нативного представления в какое-то внутреннее кроссплатформнное), они разделяются на три вида: клавиша нажата (pressed), отпущена (released) и автоповтор (repeated). Из этих нативных событий надо определить и объединить два или более в один промежуток:
скрытый текст…
/// Описывает событие нажатия-отжатия клавиши.
/// Должно содержать минимум два события: нажатие (KEYDOWN PRESSED) и отжатие (KEYUP RELEASE),
/// которые могут быть получены вызовом методов `start()` и `end()` соответственно.
/// Опционально может содержать дополнительно события автоповторения зажатой клавиши (REPEAT).
#[derive(Debug, Clone)]
pub struct KeyEventDuration {
/// Список событий, относящихся к текущему промежутку
events: Vec<Rc<KeyEvent>>,
/// Отметка о том, что событие впоследствии было стёрто (Backspace'ом или как-то иначе).
/// Должно быть вычислено и выставлено в `true`. По-умолчанию при создании - всегда `false`.
pub deleted: bool,
/// Смещение от предыдущего промежутка: (начало_текущего - начало_предыдущего)
pub offset: Option<Duration>,
}
impl KeyEventDuration {
/// All raw events that includes by this KeyDuration.
#[inline(always)]
pub fn events(&self) -> impl Iterator<Item = &KeyEvent> + '_ {
self.events.iter().map(|rc| &**rc)
}
/// Первый event для этого события (KEYDOWN)
#[inline(always)]
pub fn start(&self) -> &KeyEvent {
&self.events[0]
}
/// Последний event для этого события (KEYUP)
#[inline(always)]
pub fn end(&self) -> &KeyEvent {
&self.events[&self.events.len() - 1]
}
/// Длительность события (нажатия)
pub fn duration(&self) -> Duration {
self.end().ts.duration_since(self.start().ts).unwrap()
}
}
Затем промежутки объединить в блоки набора (это непрерывная печать в течение некоторого времени, ТС отделяет их символом
‡), внутри которых также корректно определить ошибки и исправления, в том числе с использованием
Ctrl+Backspace и другими комбинациями. И наложения посчитать )
Последний раз отредактировано 18 мая 2022 в 11:24 модератором Fenex