Криптография (общая)
Одинакова для wire 1.0–1.4 (на 1.3+ AEAD использует AAD). Меняется формат кадра после рукопожатия. Кадр транспортно-агностичен: сегодня WebSocket, в 2.0 — также UDP/TCP.
- ECDH — X25519, свежая пара ключей на сессию
- KDF — HKDF-SHA256, salt пустой; info
DVeProto-v1/c2sиDVeProto-v1/s2c - AEAD — AES-256-GCM, nonce 12 байт на каждое сообщение
- Клиент → сервер: ключ c2s. Сервер → клиент: ключ s2c.
Рукопожатие
Всегда UTF-8 JSON, одинаково для обеих версий. Поле v рукопожатия = 1.
- Сервер:
dve_helloсserver_pk, опциональноoffer: ["1.0"…"1.5"]иcaps. - Клиент считает shared secret X25519 и ключи HKDF (или resume из ticket).
- Клиент:
dve_client_ackсclient_pkиselectдо"1.5", либоresume. Безselect→ 1.0.select "1.5"≡ wire 1.4. - Дальше только выбранный wire-формат.
{
"type": "dve_hello",
"proto": "DVeProto",
"v": 1,
"server_pk": "<base64 32 bytes>",
"offer": ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"],
"caps": 2111
}
{
"type": "dve_client_ack",
"proto": "DVeProto",
"v": 1,
"client_pk": "<base64 32 bytes>",
"select": "1.5",
"caps": 2111
}
Версии wire
Выберите версию, чтобы посмотреть формат данных после рукопожатия.
Wire 1.0 — JSON text frames
reference-1.0.py · reference-1.0.js
После handshake каждое сообщение — один WebSocket text frame с JSON. Ciphertext и nonce в Base64.
- Транспорт: только text frames
- Обёртка:
type: "dve",proto,v: 1,n,c - Plaintext внутри AEAD — UTF-8 JSON объект
- Режим по умолчанию, если клиент не указал select
{
"type": "dve",
"proto": "DVeProto",
"v": 1,
"n": "<base64 12-byte nonce>",
"c": "<base64 AES-GCM ciphertext||tag>"
}
Подходит для каналов без binary frames и для максимальной совместимости со старыми клиентами.
Wire 1.1 — binary frames
reference-1.1.py · reference-1.1.js
После handshake данные идут только binary WebSocket frames. Без JSON и Base64 на wire.
- Транспорт: только binary frames (opcode 0x2)
- Длина сообщения = граница кадра
verвсегда0x11- Чанковая передача файлов (FILE_*)
[1] ver = 0x11 [1] ptype [12] nonce […] ciphertext || GCM-tag(16)
ptype
| ptype | Имя | Назначение |
|---|---|---|
0x01 | APP_JSON | UTF-8 JSON / RPC |
0x02 | APP_BIN | Произвольные байты |
0x03 | TEXT | UTF-8 текст |
0x10 | FILE_BEGIN | Старт файла |
0x11 | FILE_CHUNK | Чанк |
0x12 | FILE_END | Конец |
0x13 | FILE_ABORT | Отмена |
0x14 | FILE_ACK | ACK / resume |
0x15 | FILE_RESUME | Продолжить с чанка |
Файлы
FILE_BEGIN → FILE_CHUNK* → FILE_END. Каждый chunk — отдельный binary frame со своим nonce/tag. Resume: FILE_RESUME / FILE_ACK. Чанк по умолчанию 256 KiB.
FILE_BEGIN: transfer_id[16] | file_size u64be | chunk_size u32be | total_chunks u32be | flags u8 | name_len u16be | name | mime_len u16be | mime | [sha256 32 if flags&1] FILE_CHUNK: transfer_id[16] | chunk_index u32be | data FILE_END: transfer_id[16] | sha256[32] FILE_ABORT: transfer_id[16] | reason_code u8 FILE_ACK: transfer_id[16] | status u8 | last_ok u32be FILE_RESUME: transfer_id[16] | from_chunk u32be
Wire 1.2 — binary + mux
reference-1.2.py · reference-1.2.js
Как 1.1, плюс stream_id в заголовке, control-кадры и зарезервированные ptype под DVeNet/DVeVPN (2.0).
- Транспорт: только binary frames
ver=0x12, затемptype,stream_idu16be, nonce, ciphertext||tag- Mux: несколько логических потоков в одной DVe-сессии
- PING / PONG / CLOSE; NET_* и VPN_PKT зарезервированы до 2.0
[1] ver = 0x12 [1] ptype [2] stream_id u16be [12] nonce […] ciphertext || GCM-tag(16)
ptype (дополнительно к 1.1)
| ptype | Имя | Назначение |
|---|---|---|
0x20 | NET_CTRL | DVeNet control (2.0) |
0x21 | NET_PKT | DVeNet packet (2.0) |
0x22 | VPN_PKT | DVeVPN IP/Eth (2.0) |
0x30 | PING | Keepalive; ответ PONG |
0x31 | PONG | Ответ на PING |
0x32 | CLOSE | code u16be + reason |
DVeNet и DVeVPN — слой поверх 1.2; спецификация их кадров появится в протоколе 2.0.
Wire 1.3 — AAD + counter + flow control
reference-1.3.py · reference-1.3.js
Макет как у 1.2 (ver=0x13), плюс AAD в AES-GCM, счётчик nonce и WINDOW_UPDATE.
- AAD =
ver|ptype|stream_id(4 байта) - Nonce = prefix(4) || counter u64be (на направление)
- WINDOW_UPDATE 0x33: credit u32be на stream
- Начальное окно 256 KiB; PING/PONG/CLOSE/WINDOW не тратят credit
[1] ver = 0x13 [1] ptype [2] stream_id u16be [12] nonce = prefix4 || counter u64be […] ciphertext || GCM-tag(16) AAD: ver | ptype | stream_id
Wire 1.4 — final 1.x (Resume + Priority + Caps)
reference-1.4.py · reference-1.4.js
Последняя версия поколения 1.x. Дальше — только 2.0 (DVeNet / DVeVPN / UDP+TCP). Кадр готов к любому носителю.
ver=0x14+pkt_sequ32be; AAD = ver|ptype|stream_id|pkt_seq- Session Resume: SESSION_TICKET → reconnect без полного ECDH
- STREAM_PRIORITY / STREAM_CANCEL / DATA_ACK; PING с timestamp → RTT
- Capability flags; Statistics API; NET/VPN ptypes по-прежнему reserved до 2.0
[1] ver = 0x14 [1] ptype [2] stream_id u16be [4] pkt_seq u32be [12] nonce = prefix4 || counter u64be […] ciphertext || GCM-tag(16) AAD: ver | ptype | stream_id | pkt_seq Carriers (same frame body): WebSocket — 1 message = 1 frame (1.x default) TCP 2.0 — u32be length + frame UDP 2.0 — 1 datagram = 1 frame
ptype (дополнительно к 1.3)
| ptype | Имя | Назначение |
|---|---|---|
0x34 | STREAM_PRIORITY | priority u8 (0…3) |
0x35 | STREAM_CANCEL | reason + note |
0x36 | DATA_ACK | last_seq u32be |
0x37 | SESSION_TICKET | session_id + token |
0x38 | CAPS | caps u32be |
Стек к 2.0: Application → DVeNet → DVeProto 2.0 → UDP/TCP/WS → Internet. 1.4 остаётся зрелым транспортом для FlowChat и других сервисов ServerSystem.
Package 1.5 LTS — Wire Freeze
reference-1.5.py · reference-1.5.js · reference.py
Финальный релиз поколения 1.x. Binary wire = 1.4 (ver=0x14). select "1.5" — LTS-метка того же кадра.
- Wire Format Freeze: макет кадра и карта ptype заморожены; изменения — только в 2.x
- Session Ticket Store + auto Resume; Production API: send / receive / stats / close / rekey
- Security limits: max frame/lifetime, soft idle, replay window, ticket TTL clamp
- Векторы: test_vectors.json · smoke: interop_smoke.py
select "1.5" ≡ wire 1.4 / ver=0x14 package = 1.5 LTS next major = 2.0 (DVeNet / DVeVPN / UDP+TCP) DVeProto 1.5 LTS is the final release of the first-generation transport protocol. Future network-layer features are developed in DVeProto 2.x.
Эталонный код
Референс-реализации в этой же папке — без привязки к конкретному продукту.
Python
DVeClientSession.from_server_hello_text→ session + ack JSONpack_outgoing/unpack_incoming—str(1.0) илиbytes(1.1/1.2)- Хелперы
pack_file_*·pip install cryptography
session, ack = DVeClientSession.from_server_hello_text(hello_text, prefer="1.5")
frame = session.pack_outgoing({"dve_op": "ping"})
print(session.stats())
Браузер (ESM)
dveDeveloperHandshake→{ session, clientAckJson, wire }- Для 1.1–1.3
encryptOutgoing→Uint8Array
import { dveDeveloperHandshake } from './reference-client.js';
const { session, clientAckJson, wire } = await dveDeveloperHandshake(hello);
const out = await session.encryptOutgoing({ dve_op: 'ping' });
Конвенция APP_JSON
dve_op— имя операции / RPCdve_seq— опциональный монотонный счётчик (DVeSeq)
DVeProto 1.5 LTS is the final release of the first-generation transport protocol. Future network-layer features are developed in DVeProto 2.x.
DVeProto 2.0 Roadmap
roadmap-2.0.md · Release Gate · Exit Criteria · COMPATIBILITY · CHANGELOG
Статус: Beta Development — Phase 6 Discovery+Peers. Alpha 2.0 frozen. Next: Routing → Multipath → DVeVPN.
- Alpha Released ✔
- Beta Phase 6 Discovery + Peers
- Phase 7–9 Routing · Multipath · VPN
- Not now
test_discovery_channel.pyv2/dvenet.py- NodeID ≠ ConnectionID
- 1.5 LTS + Alpha freeze
Smart Transport: события Carrier; полноценно с DVeNet (Beta+).
Applications
↓
FlowChat / DVeRPC / File Transfer
↓
DVeNet (+ Smart Transport) ← Beta (after Alpha Released)
↓
DVeVPN ← RC
↓
Handshake 2.0 + Wire 2.0 ← AC1 / Alpha
↓
Carrier: UDP | TCP
↓
Internet
Совместимость
Клиенты без select работают на 1.0. Выбирается высший общий wire (до 1.4). 1.5 LTS — тот же binary, что 1.4; после LTS wire 1.x замораживается.
Security Considerations
- Nonce 1.3+: prefix(4)||counter u64 — без повторного (key, nonce); переполнение → закрытие сессии.
- pkt_seq в AAD (1.4); дубликаты/окно — на усмотрение реализации, без reuse nonce.
- SESSION_TICKET TTL по умолчанию 24ч; привязка к identity; expired/bad → dve_resume_reject.
- AEAD + counter nonce ограничивают replay; после Resume ключи новые (resume HKDF).
- Клиенты, требующие 1.4+, обязаны прервать сессию при более низком select.
Тестовые векторы: test_vectors.json · gen_test_vectors.py.