SHA256
homeserver: рендейм subserver→homeserver, документ деривации ключей, запрет пустого пароля
Основное (наша работа в этой сессии): - Переименование «subserver» → «homeserver» по всему проекту: основной ESP32-скетч (папка shine_subserver_ui → shine_homeserver_ui, .ino, flash-скрипт, режим burn.sh homeserver-ui), скетч lvgl_nav_minimal_test (ключ homeserver.key:<имя>), spec-доки reference/*, формат PDA (терминология session_type=100 «Homeserver пользователя»), константа SESSION_TYPE_HOMESERVER в JS и Rust (значение 100 не менялось, формат не затронут), pending/future доки, AGENTS.md, DAO-док. Сохранены отдельный lvgl_subserver_touch_test и историческая пометка о рендейме в DERIVATION.md. - Новый источник истины по деривации ключей: Dev_Docs/Keys/DERIVATION.md (Argon2id-секрет из пароля, формула Ed25519(SHA-256(base64(secret)|suffix)), суффиксы root/bch/dev/homeserver.key, Solana-ключ = dev.key). Уточнены роли root (главный/master) и dev (пополняемый кошелёк) в Dev_Docs/Keys/README.md. - UI: убран легаси-путь пустого пароля (derivePasswordSeed и др.), deriveMasterSecretFromPassword бросает ошибку на пустом пароле, register-view блокирует пустой пароль; экран пополнения переведён на канонический device-адрес из preGeneratedKeyBundle (удалён расходящийся deriveWalletFromPassword). Включены также параллельные правки Solana-аудита №3 (были в рабочем дереве, переплетены в lib.rs): - shine_users: defense-in-depth «строгий список аккаунтов» (require!(it.next().is_none())) в init/update economy config и create/update user PDA, плюс описание в doc/programs/shine_users.md; - Dev_Docs/audit/Solana-audit-3-by-Claude-12июня2026.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cf6a2830c8
commit
42dcf6970d
@@ -0,0 +1,154 @@
|
||||
# Деривация секрета и ключей SHiNE (формулы)
|
||||
|
||||
> **Статус: ИСТОЧНИК ИСТИНЫ (single source of truth) по конкретной деривации.**
|
||||
> Этот файл описывает, как из пароля получается секрет и как из секрета выводятся
|
||||
> все ключи (root, blockchain, device/Solana, homeserver) — формулами, байт-в-байт.
|
||||
> Если в коде меняется деривация (формула секрета, параметры Argon2id, соль, формула
|
||||
> ключа, разделитель `|`, набор/имена суффиксов, формат homeserver-ключа, связь
|
||||
> dev-ключ ↔ Solana-адрес) — **в том же изменении обязательно править этот документ**.
|
||||
> Роли и назначение ключей описаны отдельно в `Dev_Docs/Keys/README.md` (архитектура).
|
||||
> Здесь — только механика. Документ намеренно краткий.
|
||||
|
||||
---
|
||||
|
||||
## 1. Секрет (masterSecret)
|
||||
|
||||
`masterSecret` — 32 байта. Два источника:
|
||||
|
||||
**А. Из пароля пользователя (основной путь, UI).**
|
||||
|
||||
```
|
||||
login = trim(lowercase(login))
|
||||
salt = SHA-256("shine-auth-v2|login=" + login + "|suffix=master.secret")[0..16) // первые 16 байт
|
||||
material = utf8(login + "\n" + password)
|
||||
masterSecret(32) = Argon2id(material, salt, t=2, m=65536 KiB, p=1, dkLen=32)
|
||||
```
|
||||
|
||||
- Параметры Argon2id фиксированы: `t=2`, `m=65536` (64 МиБ), `p=1`, `dkLen=32`.
|
||||
- Логин входит и в соль, и в начало `material` (склейка через `\n`).
|
||||
- Пустой пароль **запрещён**: легаси-fallback без Argon2 удалён, `deriveMasterSecretFromPassword` бросает ошибку на пустом пароле, а форма регистрации в UI блокирует пустой пароль (`register-view.js`).
|
||||
|
||||
**Б. Случайный (прошивка ESP32, новый аккаунт без пароля).**
|
||||
|
||||
```
|
||||
masterSecret(32) = 32 случайных байта (esp_random) // хранится на устройстве как base58
|
||||
```
|
||||
|
||||
Дальше деривация ключей одинакова независимо от источника секрета.
|
||||
|
||||
---
|
||||
|
||||
## 2. Производные ключи
|
||||
|
||||
Все ключи выводятся из `masterSecret` по **одной формуле**, отличается только суффикс:
|
||||
|
||||
```
|
||||
material = base64_std(masterSecret) + "|" + <суффикс>
|
||||
seed(32) = SHA-256(material)
|
||||
(pub, priv) = Ed25519_keypair_from_seed(seed)
|
||||
```
|
||||
|
||||
- `base64_std` — стандартный base64 (не url-safe).
|
||||
- Разделитель — символ `|`.
|
||||
- Суффиксы значимы байт-в-байт (регистр и точки важны).
|
||||
|
||||
| Ключ | Суффикс | Назначение (кратко) |
|
||||
|------|---------|---------------------|
|
||||
| root | `root.key` | Личность. Подписывает unsigned-часть PDA-записи (`RootKeyBlock`). |
|
||||
| blockchain | `bch.key` | Подписывает `LastBlockState` персонального блокчейна (`blockchain_public_key`). |
|
||||
| device / **Solana** | `dev.key` | Ключ устройства = Solana-ключ. Fee payer и подпись Solana-транзакций; адрес кошелька = `base58(devicePub)`. См. §3. |
|
||||
| homeserver | `homeserver.key:<имя>` | Ключ homeserver-устройства, по одному на каждый homeserver (различитель — имя). См. §4. |
|
||||
|
||||
Полные роли каждого ключа — в `Dev_Docs/Keys/README.md`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Solana-ключ
|
||||
|
||||
Отдельного «солана-ключа» нет. На Solana работают два ключа:
|
||||
|
||||
- **`dev.key` (device) — пополняемый кошелёк и fee payer.** Solana-адрес = `base58(devicePub)`.
|
||||
Этим ключом оплачиваются и подписываются `create_user_pda` / `update_user_pda`.
|
||||
Пополнять SOL нужно именно на этот адрес.
|
||||
- **`root.key` — авторитет записи**, подписывает unsigned-часть PDA через Ed25519-инструкцию, но **не** является fee payer.
|
||||
|
||||
Соответствует формату PDA `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md` §2.1
|
||||
(«create/update оплачиваются с `device_key`», «root_key — не fee payer»).
|
||||
|
||||
Кратко про роли на Solana: `root.key` — это **главный (master) ключ**: им управляют PDA-записью
|
||||
(`create/update`) и через это можно заменить все остальные ключи; `dev.key` — это **пополняемый
|
||||
кошелёк и плательщик комиссий**. Полное описание ролей — `Dev_Docs/Keys/README.md`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Ключи homeserver
|
||||
|
||||
У пользователя может быть несколько homeserver-ов. Каждый имеет **своё имя** и **свой приватный ключ**,
|
||||
выведенный из секрета по той же формуле с именованным суффиксом:
|
||||
|
||||
```
|
||||
suffix = "homeserver.key:" + <имя homeserver> // имя по умолчанию: "homeserver1"
|
||||
material = base64_std(masterSecret) + "|" + suffix
|
||||
seed(32) = SHA-256(material)
|
||||
(pub, priv) = Ed25519_keypair_from_seed(seed)
|
||||
```
|
||||
|
||||
Пример для двух homeserver-ов:
|
||||
|
||||
```
|
||||
homeserver.key:home-a -> ключ A
|
||||
homeserver.key:home-b -> ключ B
|
||||
```
|
||||
|
||||
Публичный ключ homeserver-а публикуется в `SessionsBlock` пользовательской PDA как
|
||||
`session_pub_key` с `session_type = 100`, имя — в `session_name` (формат PDA §13).
|
||||
|
||||
> Это переименование прежней схемы `subserver.key:<имя>` → `homeserver.key:<имя>`.
|
||||
> Термин «саб-сервер» по проекту заменяется на «homeserver».
|
||||
|
||||
---
|
||||
|
||||
## 5. Где это в коде
|
||||
|
||||
### Деривация секрета и ключей (UI, каноническая)
|
||||
- `shine-UI/js/services/crypto-utils.js`
|
||||
- секрет из пароля: `makeArgon2Salt`, `deriveMasterSecretArgon2id`, `deriveMasterSecretFromPassword` (~129–218);
|
||||
- ключ из секрета: `deriveEd25519FromMasterSecret` (~220).
|
||||
- `shine-UI/js/services/auth-service.js` — набор root/bch/dev из `masterSecret` (~732–758).
|
||||
- `shine-UI/server-ui/js/server-ui-shared.js` — те же root/bch/dev для серверного UI (~147–160).
|
||||
|
||||
### Solana-ключ / адрес кошелька (UI)
|
||||
- `shine-UI/js/pages/registration-payment-view.js` — `deriveUserWalletAddress`: адрес = `base58(devicePub)` (~113).
|
||||
- `shine-UI/js/pages/topup-view.js` — `deviceWalletAddressFromBundle`: тот же канонический адрес из `preGeneratedKeyBundle.devicePair`.
|
||||
Прежний расходящийся путь `deriveWalletFromPassword` (прямой Argon2 по `dev.key`, мимо `masterSecret`) удалён.
|
||||
|
||||
### Деривация ключей (прошивка ESP32)
|
||||
- `ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/shine_homeserver_ui/shine_homeserver_ui.ino`
|
||||
- `deriveKeysFromMasterSecret` (~782), `restoreDerivedKeysFromSecret` (~806), `deriveFreshSecretAndWallet` (~829);
|
||||
- регистрация/подпись Solana: `registerHomeserverOnSolana` (~1182), `signMessageEd25519` (~1147).
|
||||
- `ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_nav_minimal_test/lvgl_nav_minimal_test.ino`
|
||||
- homeserver-ключ: `homeserverKeySuffix` (~690), `deriveKeyPairFromSecretSuffix` (~699), `refreshDerivedKeys` (~725); суффикс `homeserver.key:<имя>`.
|
||||
|
||||
### Формат PDA (куда попадают ключи)
|
||||
- `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md`
|
||||
— `RootKeyBlock` §6, `DeviceKeyBlock` §7, `blockchain_public_key` §9, `SessionsBlock`/`session_type=100` §13, оплата §2.1.
|
||||
|
||||
### Сервер (тестовый seed)
|
||||
- `SHiNE-server/src/test/java/test/it/cases/SeedDataPopulationHelper.java` `deriveKeysFromPassword` (~246) —
|
||||
выводит ключи как `Ed25519(SHA-256(base64(SHA-256(password)) + suffix))`, **без** Argon2 и **без** разделителя `|`.
|
||||
Это **не баг**, а точное повторение легаси-пути UI `derivePasswordSeed` (для пустого пароля), у которого тоже нет `|`.
|
||||
С современным путём `masterSecret`-bundle (Argon2 + `base64(secret)|suffix`) он **не совпадает** by design.
|
||||
Если потребуется, чтобы seed совпадал с реальными клиентами на Argon2 — нужно отдельно портировать
|
||||
Argon2id+masterSecret в Java (на сервере Argon2 сейчас нет). Простое добавление `|` было бы **неверным**:
|
||||
сломало бы совпадение с легаси-путём и всё равно не дало бы совпадения с Argon2-путём.
|
||||
|
||||
---
|
||||
|
||||
## 6. Правило синхронизации (обязательно)
|
||||
|
||||
1. Этот документ — источник истины по деривации секрета и ключей.
|
||||
2. Любое изменение кода, затрагивающее формулу секрета, параметры Argon2id, соль, формулу ключа,
|
||||
разделитель `|`, набор/имена суффиксов, формат homeserver-ключа или связь dev-ключ ↔ Solana-адрес —
|
||||
**обязательно** отражать здесь в том же изменении.
|
||||
3. Пункты, помеченные ⚠️, — это долг к устранению, а не норма.
|
||||
4. Нельзя сознательно оставлять код и этот документ в рассинхроне без отдельной явной договорённости.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
В SHiNE у пользователя есть несколько уровней ключей:
|
||||
|
||||
- `root key` - главный корневой ключ пользователя, он же основной Solana-ключ.
|
||||
- `root key` - главный (master) ключ пользователя: тот, кто им владеет, управляет пользовательской PDA в Solana и может заменить все остальные ключи. Это не пополняемый кошелёк (комиссии платит `device key`).
|
||||
- `blockchain key` - ключ записи в персональный SHiNE-блокчейн пользователя.
|
||||
- `device key` - общий ключ пользовательских устройств для повседневной работы, звонков, DM и мелких платежей.
|
||||
- `session key` - ключ конкретной сессии или конкретного устройства для авторизации на сервере.
|
||||
@@ -28,9 +28,9 @@
|
||||
- управление остальными ключами;
|
||||
- подтверждение операций, которые должны иметь максимальный уровень доверия.
|
||||
|
||||
В текущей модели `root key` совпадает по смыслу с главным Solana-ключом пользователя.
|
||||
`root key` — это **главный (master) ключ** в следующем смысле: зная `root key`, можно управлять пользовательской PDA-записью в Solana (`create_user_pda` / `update_user_pda`) и тем самым **заменить все остальные ключи** пользователя (device, blockchain, homeserver). Поэтому компрометация `root key` равносильна компрометации всей личности пользователя.
|
||||
|
||||
На `root key` могут храниться значимые средства, если пользователь сознательно выбирает такую модель. Для мелких текущих расходов предпочтительнее использовать `device key`.
|
||||
Важно не путать авторитет и кошелёк: `root key` — это авторитет над PDA-записью, а **SOL-комиссии за create/update платит `device key`** (он же fee payer и адрес для пополнения). Подробнее о том, какой ключ за что отвечает на Solana, — в `Dev_Docs/Keys/DERIVATION.md`, §3.
|
||||
|
||||
## `blockchain key`
|
||||
|
||||
@@ -158,6 +158,7 @@ Self-message - это сообщение пользователя самому
|
||||
|
||||
## Связанные документы
|
||||
|
||||
- `Dev_Docs/Keys/DERIVATION.md` - **источник истины по конкретной деривации** секрета и ключей (формулы Argon2id, `base64|suffix→SHA-256→Ed25519`, суффиксы `root.key`/`bch.key`/`dev.key`/`homeserver.key:<имя>`, Solana-ключ, ссылки на код).
|
||||
- `Dev_Docs/Personal_Messages/README.md` - текущая документация личных сообщений.
|
||||
- `Dev_Docs/Blockchain/README.md` - точка входа по форматам SHiNE-блокчейна.
|
||||
- `Dev_Docs/Solana_Architecture/README.md` - архитектура Solana-программ, PDA-счетов, DAO и движения средств.
|
||||
|
||||
Reference in New Issue
Block a user