Парольная политика (ADR-013) и привязка экспорта к аккаунту (ADR-014)

ADR-013: PBKDF2-HMAC-SHA256 ≥600k итераций (цель 1M), параметры KDF
версионируются рядом с блобом; пароль от 12 символов, длина важнее
состава. ADR-014: парольная фраза экспорта отменена, ключ экспорта —
HKDF от 32-байтового секрета аккаунта из ключевого блоба; архив .bare
криптографически бесполезен вне аккаунта-владельца. Перекрёстно
обновлены ADR-006, ADR-010, architecture, threat-model; в открытые
вопросы добавлен серверный «перец» для блоба.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SW4ZXtKn5NjX8NH3Lhm2ND
This commit is contained in:
Claude
2026-08-20 09:41:33 +00:00
co-authored by Claude Fable 5
parent 700256c8ef
commit b9bf4ea04e
7 changed files with 55 additions and 5 deletions
+6 -2
View File
@@ -14,11 +14,13 @@ Bare — это PWA-клиент на ванильных веб-технолог
Серверная аутентификация: Argon2id, сессия в httpOnly cookie.
Пароль — не короче 12 символов; правил про регистры и спецсимволы нет: длина важнее состава. UI рекомендует парольную фразу из нескольких слов и при регистрации прямо говорит: пароль — это ключ шифрования, а не запись в базе; восстановления нет.
## E2EE
Вся клиентская криптография — WebCrypto, без крипто-библиотек.
Идентичность пользователя — ECDH-пара (P-256). Приватный ключ шифруется ключом, выведенным из пароля (PBKDF2), и хранится на сервере как блоб — сервер видит только шифротекст. Отсюда два следствия. Сброс пароля невозможен by design. Мультидевайс-вход прост: новый девайс вводит пароль, скачивает блоб, расшифровывает ключ.
Идентичность пользователя — ECDH-пара (P-256). Приватный ключ шифруется ключом, выведенным из пароля (PBKDF2-HMAC-SHA256, не менее 600 000 итераций, целевое значение — 1 000 000), и хранится на сервере как блоб — сервер видит только шифротекст. Параметры KDF лежат рядом с блобом и читаются клиентом при входе: их можно повышать без миграции всех аккаунтов разом. Рядом с приватным ключом в блобе живёт случайный 32-байтовый секрет аккаунта — из него выводятся ключи экспорта истории. Отсюда два следствия. Сброс пароля невозможен by design. Мультидевайс-вход прост: новый девайс вводит пароль, скачивает блоб, расшифровывает ключ.
Чаты 1:1: ECDH shared secret → AES-GCM.
@@ -36,7 +38,9 @@ Forward secrecy — осознанный non-goal v1.
## Экспорт и импорт истории
Экспорт: вся локальная история сериализуется, шифруется отдельной парольной фразой (запрашивается в момент экспорта) и сохраняется одним файлом `.bare`. Импорт: файл плюс фраза, merge в IndexedDB по messageId, идемпотентно — повторный импорт и склейка истории с двух устройств не создают дублей.
Экспорт: вся локальная история сериализуется, шифруется и сохраняется одним файлом `.bare`. Ключ экспорта выводится из секрета аккаунта: HKDF(секрет, случайный salt, info="bare-export-v1") → AES-GCM, всё на WebCrypto. Отдельной парольной фразы нет: архив криптографически привязан к аккаунту и вне его бесполезен — у чужого клиента нет секрета аккаунта, расшифровка невозможна в принципе.
Заголовок файла открытый: magic, версия формата, salt, отпечаток публичного ключа владельца. Ника в заголовке нет — лишняя утечка. Импорт: клиент сверяет отпечаток со своим (при несовпадении — «архив создан другим аккаунтом», сверка — UX-вежливость, не защита) и делает идемпотентный merge в IndexedDB по messageId — повторный импорт и склейка истории с двух устройств не создают дублей.
Это единственный механизм переноса истории между устройствами. Осознанно.